fix: clj_ prefix for identifiers + try/catch/finally fixes
- #9: Add clj_ prefix to all mangled identifiers to avoid Nim case-insensitive name conflicts (parseQueryString ≡ parse_query_string) - #11: Fix finally block - discard expression results - #11: Fix catch handler - use original name for scope tracking - Fix loop handler - use original name for addToScope - Update emitter tests for clj_ prefix
This commit is contained in:
+19
-9
@@ -79,6 +79,8 @@ proc mangleName*(name: string): string =
|
|||||||
"interface", "lambda", "open", "quit", "result", "nil", "end"]
|
"interface", "lambda", "open", "quit", "result", "nil", "end"]
|
||||||
if result in nimKeywords:
|
if result in nimKeywords:
|
||||||
result = result & "1"
|
result = result & "1"
|
||||||
|
# Prefix to avoid conflicts with Nim identifiers (case-insensitive + underscore ignoring)
|
||||||
|
result = "clj_" & result
|
||||||
|
|
||||||
proc pushScope() =
|
proc pushScope() =
|
||||||
scopeStack.add(initHashSet[string]())
|
scopeStack.add(initHashSet[string]())
|
||||||
@@ -1165,7 +1167,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
raise newException(EmitterError, "loop bindings must be a vector")
|
raise newException(EmitterError, "loop bindings must be a vector")
|
||||||
if bindings.items.len mod 2 != 0:
|
if bindings.items.len mod 2 != 0:
|
||||||
raise newException(EmitterError, "loop bindings must have even number of elements")
|
raise newException(EmitterError, "loop bindings must have even number of elements")
|
||||||
var loopParams: seq[(string, string)] = @[]
|
var loopParams: seq[(string, string, string)] = @[] # (mangled, original, value)
|
||||||
var li = 0
|
var li = 0
|
||||||
while li < bindings.items.len:
|
while li < bindings.items.len:
|
||||||
var lname = bindings.items[li]
|
var lname = bindings.items[li]
|
||||||
@@ -1175,13 +1177,13 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
lname = lname.items[1]
|
lname = lname.items[1]
|
||||||
if lname.kind != ckSymbol:
|
if lname.kind != ckSymbol:
|
||||||
raise newException(EmitterError, "loop binding name must be a symbol")
|
raise newException(EmitterError, "loop binding name must be a symbol")
|
||||||
loopParams.add((mangleName(lname.symName), emitExpr(lval, 0)))
|
loopParams.add((mangleName(lname.symName), lname.symName, emitExpr(lval, 0)))
|
||||||
li += 2
|
li += 2
|
||||||
var loopVars: seq[string] = @[]
|
var loopVars: seq[string] = @[]
|
||||||
var lines: seq[string] = @[]
|
var lines: seq[string] = @[]
|
||||||
pushScope()
|
pushScope()
|
||||||
for (lpName, lpVal) in loopParams:
|
for (lpName, lpOrig, lpVal) in loopParams:
|
||||||
addToScope(lpName)
|
addToScope(lpOrig)
|
||||||
lines.add(sp & "var " & lpName & ": CljVal = " & lpVal)
|
lines.add(sp & "var " & lpName & ": CljVal = " & lpVal)
|
||||||
loopVars.add(lpName)
|
loopVars.add(lpName)
|
||||||
loopStack.add(loopVars)
|
loopStack.add(loopVars)
|
||||||
@@ -1271,7 +1273,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
if items.len < 2:
|
if items.len < 2:
|
||||||
raise newException(EmitterError, "try requires body")
|
raise newException(EmitterError, "try requires body")
|
||||||
var bodyForms: seq[CljVal] = @[]
|
var bodyForms: seq[CljVal] = @[]
|
||||||
var catchClauses: seq[(string, string, seq[CljVal])] = @[]
|
var catchClauses: seq[(string, string, string, seq[CljVal])] = @[] # (exType, mangledName, origName, body)
|
||||||
var finallyBody: seq[CljVal] = @[]
|
var finallyBody: seq[CljVal] = @[]
|
||||||
var ti = 1
|
var ti = 1
|
||||||
while ti < items.len:
|
while ti < items.len:
|
||||||
@@ -1304,7 +1306,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
let exName = form.items[nameIdx]
|
let exName = form.items[nameIdx]
|
||||||
if exName.kind != ckSymbol:
|
if exName.kind != ckSymbol:
|
||||||
raise newException(EmitterError, "catch name must be a symbol")
|
raise newException(EmitterError, "catch name must be a symbol")
|
||||||
catchClauses.add((exTypeStr, mangleName(exName.symName), form.items[bodyIdx..^1]))
|
catchClauses.add((exTypeStr, mangleName(exName.symName), exName.symName, form.items[bodyIdx..^1]))
|
||||||
elif form.items[0].symName == "finally":
|
elif form.items[0].symName == "finally":
|
||||||
finallyBody = form.items[1..^1]
|
finallyBody = form.items[1..^1]
|
||||||
else:
|
else:
|
||||||
@@ -1330,7 +1332,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
lines.add(code)
|
lines.add(code)
|
||||||
else:
|
else:
|
||||||
lines.add(indentStr(indent + 1) & "discard " & stripped)
|
lines.add(indentStr(indent + 1) & "discard " & stripped)
|
||||||
for (exType, exVar, exBody) in catchClauses:
|
for (exType, exVar, exOrig, exBody) in catchClauses:
|
||||||
lines.add(sp & "except " & exType & ":")
|
lines.add(sp & "except " & exType & ":")
|
||||||
lines.add(indentStr(indent + 1) & "let " & exVar & " = cljMap(@[cljKeyword(\"message\")], @[cljString(getCurrentExceptionMsg())])")
|
lines.add(indentStr(indent + 1) & "let " & exVar & " = cljMap(@[cljKeyword(\"message\")], @[cljString(getCurrentExceptionMsg())])")
|
||||||
lines.add(indentStr(indent + 1) & "discard cljAssoc(" & exVar & ", cljKeyword(\"type\"), cljString(\"" & exType & "\"))")
|
lines.add(indentStr(indent + 1) & "discard cljAssoc(" & exVar & ", cljKeyword(\"type\"), cljString(\"" & exType & "\"))")
|
||||||
@@ -1338,7 +1340,7 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
lines.add(indentStr(indent + 1) & "if exPtr" & exVar & " of ExInfo:")
|
lines.add(indentStr(indent + 1) & "if exPtr" & exVar & " of ExInfo:")
|
||||||
lines.add(indentStr(indent + 2) & "discard cljAssoc(" & exVar & ", cljKeyword(\"data\"), (ref ExInfo)(exPtr" & exVar & ").exData)")
|
lines.add(indentStr(indent + 2) & "discard cljAssoc(" & exVar & ", cljKeyword(\"data\"), (ref ExInfo)(exPtr" & exVar & ").exData)")
|
||||||
pushScope()
|
pushScope()
|
||||||
addToScope(exVar)
|
addToScope(exOrig)
|
||||||
for i, eb in exBody:
|
for i, eb in exBody:
|
||||||
let isLast = (i == exBody.len - 1)
|
let isLast = (i == exBody.len - 1)
|
||||||
let code = emitExpr(eb, indent + 1)
|
let code = emitExpr(eb, indent + 1)
|
||||||
@@ -1359,7 +1361,15 @@ proc emitSpecialForm(items: seq[CljVal], indent: int): string =
|
|||||||
if finallyBody.len > 0:
|
if finallyBody.len > 0:
|
||||||
lines.add(sp & "finally:")
|
lines.add(sp & "finally:")
|
||||||
for fb in finallyBody:
|
for fb in finallyBody:
|
||||||
lines.add(emitExpr(fb, indent + 1))
|
let fbCode = emitExpr(fb, indent + 1)
|
||||||
|
let fbStripped = fbCode.strip()
|
||||||
|
if fbStripped.startsWith("echo ") or fbStripped.startsWith("discard ") or
|
||||||
|
fbStripped.startsWith("var ") or fbStripped.startsWith("let ") or
|
||||||
|
fbStripped.startsWith("proc ") or fbStripped.startsWith("if ") or
|
||||||
|
fbStripped.startsWith("try:") or fbStripped.startsWith("while "):
|
||||||
|
lines.add(fbCode)
|
||||||
|
else:
|
||||||
|
lines.add(indentStr(indent + 1) & "discard " & fbStripped)
|
||||||
return lines.join("\n")
|
return lines.join("\n")
|
||||||
|
|
||||||
of "throw":
|
of "throw":
|
||||||
|
|||||||
@@ -43,13 +43,13 @@ suite "Emitter - Basic Values":
|
|||||||
registerGlobal("x")
|
registerGlobal("x")
|
||||||
let v = cljSymbol("x")
|
let v = cljSymbol("x")
|
||||||
let code = emitExpr(v)
|
let code = emitExpr(v)
|
||||||
check code == "x"
|
check code == "clj_x"
|
||||||
|
|
||||||
test "emit mangled symbol":
|
test "emit mangled symbol":
|
||||||
registerGlobal("my-var")
|
registerGlobal("my-var")
|
||||||
let v = cljSymbol("my-var")
|
let v = cljSymbol("my-var")
|
||||||
let code = emitExpr(v)
|
let code = emitExpr(v)
|
||||||
check code == "my_var"
|
check code == "clj_my_var"
|
||||||
|
|
||||||
test "emit vector":
|
test "emit vector":
|
||||||
let v = cljVector(@[cljInt(1), cljInt(2)])
|
let v = cljVector(@[cljInt(1), cljInt(2)])
|
||||||
@@ -70,12 +70,12 @@ suite "Emitter - Special Forms":
|
|||||||
test "emit def":
|
test "emit def":
|
||||||
let v = read("(def x 42)")
|
let v = read("(def x 42)")
|
||||||
let code = emitExpr(v)
|
let code = emitExpr(v)
|
||||||
check "let x" in code
|
check "let clj_x" in code
|
||||||
|
|
||||||
test "emit defn":
|
test "emit defn":
|
||||||
let v = read("(defn square [x] (* x x))")
|
let v = read("(defn square [x] (* x x))")
|
||||||
let code = emitExpr(v)
|
let code = emitExpr(v)
|
||||||
check "proc square" in code
|
check "proc clj_square" in code
|
||||||
|
|
||||||
test "emit if":
|
test "emit if":
|
||||||
let v = read("(if true 1 2)")
|
let v = read("(if true 1 2)")
|
||||||
@@ -161,14 +161,14 @@ suite "Emitter - Program":
|
|||||||
test "emitProgram with defs and main":
|
test "emitProgram with defs and main":
|
||||||
let forms = readAll("(def x 42) (println x)")
|
let forms = readAll("(def x 42) (println x)")
|
||||||
let code = emitProgram(forms)
|
let code = emitProgram(forms)
|
||||||
check "let x" in code
|
check "let clj_x" in code
|
||||||
check "when isMainModule" in code
|
check "when isMainModule" in code
|
||||||
|
|
||||||
test "emitProgram multiple defs":
|
test "emitProgram multiple defs":
|
||||||
let forms = readAll("(def a 1) (def b 2)")
|
let forms = readAll("(def a 1) (def b 2)")
|
||||||
let code = emitProgram(forms)
|
let code = emitProgram(forms)
|
||||||
check "let a" in code
|
check "let clj_a" in code
|
||||||
check "let b" in code
|
check "let clj_b" in code
|
||||||
|
|
||||||
suite "Emitter - Map Literals":
|
suite "Emitter - Map Literals":
|
||||||
test "emit empty map":
|
test "emit empty map":
|
||||||
|
|||||||
Reference in New Issue
Block a user