Add string and char support
Update some comments Rename exprparser main proc Don't export parse procs Add missing utils module Try to fix array type test Try fix cast test error Disable cast test for now Revert back comment test. Have to figure out how to test without vm
This commit is contained in:
parent
62c68d69ee
commit
173e6d625c
5 changed files with 120 additions and 23 deletions
|
|
@ -18,7 +18,7 @@ proc getPtrType*(str: string): string =
|
||||||
str
|
str
|
||||||
|
|
||||||
proc getLit*(nimState: NimState, str: string, expression = false): PNode =
|
proc getLit*(nimState: NimState, str: string, expression = false): PNode =
|
||||||
result = nimState.codeToNode(str)
|
result = nimState.parseCExpression(str)
|
||||||
|
|
||||||
proc getOverrideOrSkip(gState: State, node: TSNode, origname: string, kind: NimSymKind): PNode =
|
proc getOverrideOrSkip(gState: State, node: TSNode, origname: string, kind: NimSymKind): PNode =
|
||||||
# Check if symbol `origname` of `kind` and `origname` has any cOverride defined
|
# Check if symbol `origname` of `kind` and `origname` has any cOverride defined
|
||||||
|
|
@ -164,7 +164,7 @@ proc addPragma(gState: State, node: TSNode, pragma: PNode, name: string, value:
|
||||||
if value.isNil:
|
if value.isNil:
|
||||||
pragma.add pident
|
pragma.add pident
|
||||||
else:
|
else:
|
||||||
var
|
let
|
||||||
colExpr = newNode(nkExprColonExpr)
|
colExpr = newNode(nkExprColonExpr)
|
||||||
colExpr.add pident
|
colExpr.add pident
|
||||||
colExpr.add value
|
colExpr.add value
|
||||||
|
|
@ -1386,7 +1386,7 @@ proc addEnum(gState: State, node: TSNode) =
|
||||||
|
|
||||||
if en.len > 1 and en[1].getName() in gEnumVals:
|
if en.len > 1 and en[1].getName() in gEnumVals:
|
||||||
# Explicit value
|
# Explicit value
|
||||||
fval = "(" & gState.getNimExpression(gState.getNodeVal(en[1]), name) & ")." & name
|
fval = "(" & $gState.parseCExpression(gState.getNodeVal(en[1]), name) & ")." & name
|
||||||
|
|
||||||
# Cannot use newConstDef() since parseString(fval) adds backticks to and/or
|
# Cannot use newConstDef() since parseString(fval) adds backticks to and/or
|
||||||
gState.constSection.add gState.parseString(&"const {fname}* = {fval}")[0][0]
|
gState.constSection.add gState.parseString(&"const {fname}* = {fval}")[0][0]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import strformat, strutils, macros
|
import strformat, strutils, macros, sets
|
||||||
|
|
||||||
import regex
|
import regex
|
||||||
|
|
||||||
|
|
@ -12,11 +12,12 @@ type
|
||||||
ExprParser* = ref object
|
ExprParser* = ref object
|
||||||
state*: NimState
|
state*: NimState
|
||||||
code*: string
|
code*: string
|
||||||
|
name*: string
|
||||||
|
|
||||||
ExprParseError* = object of CatchableError
|
ExprParseError* = object of CatchableError
|
||||||
|
|
||||||
proc newExprParser*(state: NimState, code: string): ExprParser =
|
proc newExprParser*(state: NimState, code: string, name = ""): ExprParser =
|
||||||
ExprParser(state: state, code: code)
|
ExprParser(state: state, code: code, name: name)
|
||||||
|
|
||||||
template techo(msg: varargs[string, `$`]) =
|
template techo(msg: varargs[string, `$`]) =
|
||||||
if exprParser.state.gState.debug:
|
if exprParser.state.gState.debug:
|
||||||
|
|
@ -38,6 +39,8 @@ proc getIdent(exprParser: ExprParser, identName: string, kind = nskConst, parent
|
||||||
if ident != "_":
|
if ident != "_":
|
||||||
# Process the identifier through cPlugin
|
# Process the identifier through cPlugin
|
||||||
ident = exprParser.state.getIdentifier(ident, kind, parent)
|
ident = exprParser.state.getIdentifier(ident, kind, parent)
|
||||||
|
if exprParser.name.nBl and ident in exprParser.state.constIdentifiers:
|
||||||
|
ident = ident & "." & exprParser.name
|
||||||
if ident != "":
|
if ident != "":
|
||||||
result = exprParser.state.getIdent(ident)
|
result = exprParser.state.getIdent(ident)
|
||||||
|
|
||||||
|
|
@ -70,6 +73,58 @@ template withCodeAst(exprParser: ExprParser, body: untyped): untyped =
|
||||||
defer:
|
defer:
|
||||||
tree.tsTreeDelete()
|
tree.tsTreeDelete()
|
||||||
|
|
||||||
|
proc parseChar(charStr: string): uint8 {.inline.} =
|
||||||
|
## Parses a character literal out of a string. This is needed
|
||||||
|
## because treesitter gives unescaped characters when parsing
|
||||||
|
## strings.
|
||||||
|
if charStr.len == 1:
|
||||||
|
return charStr[0].uint8
|
||||||
|
|
||||||
|
# Handle octal, hex, unicode?
|
||||||
|
if charStr.startsWith("\\x"):
|
||||||
|
result = parseHexInt(charStr.replace("\\x", "0x")).uint8
|
||||||
|
elif charStr.len == 4: # Octal
|
||||||
|
result = parseOctInt("0o" & charStr[1 ..< charStr.len]).uint8
|
||||||
|
|
||||||
|
if result == 0:
|
||||||
|
case charStr
|
||||||
|
of "\\0":
|
||||||
|
result = ord('\0')
|
||||||
|
of "\\a":
|
||||||
|
result = 0x07
|
||||||
|
of "\\b":
|
||||||
|
result = 0x08
|
||||||
|
of "\\e":
|
||||||
|
result = 0x1B
|
||||||
|
of "\\f":
|
||||||
|
result = 0x0C
|
||||||
|
of "\\n":
|
||||||
|
result = '\n'.uint8
|
||||||
|
of "\\r":
|
||||||
|
result = 0x0D
|
||||||
|
of "\\t":
|
||||||
|
result = 0x09
|
||||||
|
of "\\v":
|
||||||
|
result = 0x0B
|
||||||
|
of "\\\\":
|
||||||
|
result = 0x5C
|
||||||
|
of "\\'":
|
||||||
|
result = '\''.uint8
|
||||||
|
of "\\\"":
|
||||||
|
result = '\"'.uint8
|
||||||
|
of "\\?":
|
||||||
|
result = 0x3F
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
if result > uint8.high:
|
||||||
|
result = uint8.high
|
||||||
|
|
||||||
|
proc getCharLit(charStr: string): PNode {.inline.} =
|
||||||
|
## Convert a character string into a proper Nim char lit node
|
||||||
|
result = newNode(nkCharLit)
|
||||||
|
result.intVal = parseChar(charStr).int64
|
||||||
|
|
||||||
proc getNumNode(number, suffix: string): PNode {.inline.} =
|
proc getNumNode(number, suffix: string): PNode {.inline.} =
|
||||||
## Convert a C number to a Nim number PNode
|
## Convert a C number to a Nim number PNode
|
||||||
result = newNode(nkNone)
|
result = newNode(nkNone)
|
||||||
|
|
@ -117,7 +172,7 @@ proc getNumNode(number, suffix: string): PNode {.inline.} =
|
||||||
else:
|
else:
|
||||||
result.intVal = parseInt(number)
|
result.intVal = parseInt(number)
|
||||||
|
|
||||||
proc processNumberLiteral*(exprParser: ExprParser, node: TSNode): PNode =
|
proc processNumberLiteral(exprParser: ExprParser, node: TSNode): PNode =
|
||||||
## Parse a number literal from a TSNode. Can be a float, hex, long, etc
|
## Parse a number literal from a TSNode. Can be a float, hex, long, etc
|
||||||
result = newNode(nkNone)
|
result = newNode(nkNone)
|
||||||
let nodeVal = node.val
|
let nodeVal = node.val
|
||||||
|
|
@ -141,17 +196,29 @@ proc processNumberLiteral*(exprParser: ExprParser, node: TSNode): PNode =
|
||||||
else:
|
else:
|
||||||
raise newException(ExprParseError, &"Could not find a number in number_literal: \"{nodeVal}\"")
|
raise newException(ExprParseError, &"Could not find a number in number_literal: \"{nodeVal}\"")
|
||||||
|
|
||||||
proc processCharacterLiteral*(exprParser: ExprParser, node: TSNode): PNode =
|
proc processCharacterLiteral(exprParser: ExprParser, node: TSNode): PNode =
|
||||||
result = newNode(nkCharLit)
|
let val = node.val
|
||||||
result.intVal = node.val[1].int64
|
result = getCharLit(val[1 ..< val.len - 1])
|
||||||
|
|
||||||
proc processStringLiteral*(exprParser: ExprParser, node: TSNode): PNode =
|
proc processStringLiteral(exprParser: ExprParser, node: TSNode): PNode =
|
||||||
let nodeVal = node.val
|
let
|
||||||
result = newStrNode(nkStrLit, nodeVal[1 ..< nodeVal.len - 1])
|
nodeVal = node.val
|
||||||
|
strVal = nodeVal[1 ..< nodeVal.len - 1]
|
||||||
|
|
||||||
proc processTSNode*(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode
|
const
|
||||||
|
str = "(\\\\x[[:xdigit:]]{2}|\\\\\\d{3}|\\\\0|\\\\a|\\\\b|\\\\e|\\\\f|\\\\n|\\\\r|\\\\t|\\\\v|\\\\\\\\|\\\\'|\\\\\"|[[:ascii:]])"
|
||||||
|
reg = re(str)
|
||||||
|
|
||||||
proc processShiftExpression*(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode =
|
# Convert the c string escape sequences/etc to Nim chars
|
||||||
|
var nimStr = newStringOfCap(nodeVal.len)
|
||||||
|
for m in strVal.findAll(reg):
|
||||||
|
nimStr.add(parseChar(strVal[m.group(0)[0]]).chr)
|
||||||
|
|
||||||
|
result = newStrNode(nkStrLit, nimStr)
|
||||||
|
|
||||||
|
proc processTSNode(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode
|
||||||
|
|
||||||
|
proc processShiftExpression(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode =
|
||||||
result = newNode(nkInfix)
|
result = newNode(nkInfix)
|
||||||
let
|
let
|
||||||
left = node[0]
|
left = node[0]
|
||||||
|
|
@ -185,18 +252,18 @@ proc processShiftExpression*(exprParser: ExprParser, node: TSNode, typeofNode: v
|
||||||
rightNode
|
rightNode
|
||||||
)
|
)
|
||||||
|
|
||||||
proc processParenthesizedExpr*(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode =
|
proc processParenthesizedExpr(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode =
|
||||||
result = newNode(nkPar)
|
result = newNode(nkPar)
|
||||||
for i in 0 ..< node.len():
|
for i in 0 ..< node.len():
|
||||||
result.add(exprParser.processTSNode(node[i], typeofNode))
|
result.add(exprParser.processTSNode(node[i], typeofNode))
|
||||||
|
|
||||||
proc processCastExpression*(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode =
|
proc processCastExpression(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode =
|
||||||
result = nkCast.newTree(
|
result = nkCast.newTree(
|
||||||
exprParser.processTSNode(node[0], typeofNode),
|
exprParser.processTSNode(node[0], typeofNode),
|
||||||
exprParser.processTSNode(node[1], typeofNode)
|
exprParser.processTSNode(node[1], typeofNode)
|
||||||
)
|
)
|
||||||
|
|
||||||
proc processLogicalExpression*(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode =
|
proc processLogicalExpression(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode =
|
||||||
result = newNode(nkPar)
|
result = newNode(nkPar)
|
||||||
let child = node[0]
|
let child = node[0]
|
||||||
var nimSym = ""
|
var nimSym = ""
|
||||||
|
|
@ -415,13 +482,13 @@ proc processTSNode(exprParser: ExprParser, node: TSNode, typeofNode: var PNode):
|
||||||
|
|
||||||
techo "NODE RESULT: ", result
|
techo "NODE RESULT: ", result
|
||||||
|
|
||||||
proc codeToNode*(state: NimState, code: string): PNode =
|
proc parseCExpression*(state: NimState, code: string, name = ""): PNode =
|
||||||
## Convert the C string to a nim PNode tree
|
## Convert the C string to a nim PNode tree
|
||||||
result = newNode(nkNone)
|
result = newNode(nkNone)
|
||||||
# This is used for keeping track of the type of the first
|
# This is used for keeping track of the type of the first
|
||||||
# symbol
|
# symbol
|
||||||
var tnode: PNode = nil
|
var tnode: PNode = nil
|
||||||
let exprParser = newExprParser(state, code)
|
let exprParser = newExprParser(state, code, name)
|
||||||
try:
|
try:
|
||||||
withCodeAst(exprParser):
|
withCodeAst(exprParser):
|
||||||
result = exprParser.processTSNode(root, tnode)
|
result = exprParser.processTSNode(root, tnode)
|
||||||
|
|
|
||||||
18
nimterop/utils.nim
Normal file
18
nimterop/utils.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import compiler/[ast, lineinfos, msgs, options, parser, renderer]
|
||||||
|
|
||||||
|
import "."/[globals, getters]
|
||||||
|
|
||||||
|
proc handleError*(conf: ConfigRef, info: TLineInfo, msg: TMsgKind, arg: string) =
|
||||||
|
# Raise exception in parseString() instead of exiting for errors
|
||||||
|
if msg < warnMin:
|
||||||
|
raise newException(Exception, msgKindToString(msg))
|
||||||
|
|
||||||
|
proc parseString*(nimState: NimState, str: string): PNode =
|
||||||
|
# Parse a string into Nim AST - use custom error handler that raises
|
||||||
|
# an exception rather than exiting on failure
|
||||||
|
try:
|
||||||
|
result = parseString(
|
||||||
|
str, nimState.identCache, nimState.config, errorHandler = handleError
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
decho getCurrentExceptionMsg()
|
||||||
|
|
@ -23,6 +23,12 @@ extern "C" {
|
||||||
#define BOOL true
|
#define BOOL true
|
||||||
#define MATHEXPR (1 + 2/3*20 - 100)
|
#define MATHEXPR (1 + 2/3*20 - 100)
|
||||||
#define ANDEXPR (100 & 11000)
|
#define ANDEXPR (100 & 11000)
|
||||||
|
#define CASTEXPR (int) 34
|
||||||
|
|
||||||
|
#define NULLCHAR '\0'
|
||||||
|
#define OCTCHAR '\012'
|
||||||
|
#define HEXCHAR '\xFE'
|
||||||
|
#define TRICKYSTR "\x4E\034\nfoo\0\'\"\r\v\a\b\e\f\t\\\?bar"
|
||||||
|
|
||||||
#define ALLSHL (SHL1 | SHL2 | SHL3)
|
#define ALLSHL (SHL1 | SHL2 | SHL3)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,11 +93,11 @@ macro testFields(t: typed, fields: static[string] = "") =
|
||||||
for i in 0 ..< rl.len:
|
for i in 0 ..< rl.len:
|
||||||
let
|
let
|
||||||
name = ($rl[i][0]).strip(chars = {'*'})
|
name = ($rl[i][0]).strip(chars = {'*'})
|
||||||
typ = ($(rl[i][1].repr())).replace("\n", "").replace(" ", "")
|
typ = ($(rl[i][1].repr())).replace("\n", "").replace(" ", "").replace("typeof", "type")
|
||||||
n = names.find(name)
|
n = names.find(name)
|
||||||
assert n != -1, $t & "." & name & " invalid"
|
assert n != -1, $t & "." & name & " invalid"
|
||||||
assert types[n] == typ,
|
assert types[n].replace("typeof", "type") == typ,
|
||||||
"typeof(" & $t & ":" & name & ") != " & types[n] & ", is " & typ
|
"typeof(" & $t & ":" & name & ") != " & types[n].replace("typeof", "type") & ", is " & typ
|
||||||
|
|
||||||
assert A == 2
|
assert A == 2
|
||||||
assert B == 1.0
|
assert B == 1.0
|
||||||
|
|
@ -118,6 +118,12 @@ assert BINEXPR == 5
|
||||||
assert BOOL == true
|
assert BOOL == true
|
||||||
assert MATHEXPR == -99
|
assert MATHEXPR == -99
|
||||||
assert ANDEXPR == 96
|
assert ANDEXPR == 96
|
||||||
|
assert CASTEXPR == 34.chr
|
||||||
|
|
||||||
|
assert TRICKYSTR == "N\x1C\nfoo\x00\'\"\c\v\a\b\e\f\t\\\\?bar"
|
||||||
|
assert NULLCHAR == '\0'
|
||||||
|
assert OCTCHAR == '\n'
|
||||||
|
assert HEXCHAR.int == 0xFE
|
||||||
|
|
||||||
assert SHL1 == (1.uint shl 1)
|
assert SHL1 == (1.uint shl 1)
|
||||||
assert SHL2 == (1.uint shl 2)
|
assert SHL2 == (1.uint shl 2)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue