aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Yakimowich-Payne <jyapayne@gmail.com>2020-04-16 20:49:06 -0600
committerJoey Yakimowich-Payne <jyapayne@gmail.com>2020-04-23 17:30:28 -0600
commit879c7e3c784b3debce068a93e7f9ee116eb7bc21 (patch)
tree8c0c2ef2742335369db091cfde95e1e23ac12708
parent80018f43cf35214e95c4fa777f65bb756be1db24 (diff)
downloadnimterop-879c7e3c784b3debce068a93e7f9ee116eb7bc21.tar.gz
nimterop-879c7e3c784b3debce068a93e7f9ee116eb7bc21.zip
Add preliminary expression parsing
-rw-r--r--nimterop/ast2.nim77
-rw-r--r--nimterop/exprparser.nim245
-rw-r--r--nimterop/getters.nim2
3 files changed, 253 insertions, 71 deletions
diff --git a/nimterop/ast2.nim b/nimterop/ast2.nim
index 43b6b35..04bb8eb 100644
--- a/nimterop/ast2.nim
+++ b/nimterop/ast2.nim
@@ -1,37 +1,10 @@
import macros, os, sequtils, sets, strformat, strutils, tables, times
-import regex
-
import compiler/[ast, idents, lineinfos, modulegraphs, msgs, options, parser, renderer]
-import "."/treesitter/[api, c, cpp]
-
-import "."/[globals, getters]
-
-proc getCCodeAst*(gState: State, code: string): string =
- var parser = tsParserNew()
- var code = code
+import "."/treesitter/api
- defer:
- parser.tsParserDelete()
-
-
- doAssert code.nBl, "Empty code"
- if gState.mode == "c":
- doAssert parser.tsParserSetLanguage(treeSitterC()), "Failed to load C parser"
- elif gState.mode == "cpp":
- doAssert parser.tsParserSetLanguage(treeSitterCpp()), "Failed to load C++ parser"
- else:
- doAssert false, &"Invalid parser {gState.mode}"
-
- var
- tree = parser.tsParserParseString(nil, code.cstring, code.len.uint32)
- root = tree.tsTreeRootNode()
-
- defer:
- tree.tsTreeDelete()
-
- return code.printLisp(root)
+import "."/[globals, getters, exprparser]
proc getPtrType*(str: string): string =
result = case str:
@@ -59,42 +32,8 @@ proc parseString(gState: State, str: string): PNode =
except:
decho getCurrentExceptionMsg()
-proc getLit*(gState: State, str: string, expression = false): PNode =
- # Used to convert #define literals into const and expressions
- # in array sizes
- #
- # `expression` is true when `str` should be converted into a Nim expression
- let
- str = str.replace(re"/[/*].*?(?:\*/)?$", "").strip()
-
- if str.contains(re"^[\-]?[\d]+$"): # decimal
- result = newIntNode(nkIntLit, parseInt(str))
-
- elif str.contains(re"^[\-]?[\d]*[.]?[\d]+$"): # float
- result = newFloatNode(nkFloatLit, parseFloat(str))
-
- elif str.contains(re"^0x[\da-fA-F]+$"): # hexadecimal
- result = gState.parseString(str)
-
- elif str.contains(re"^'[[:ascii:]]'$"): # char
- result = newNode(nkCharLit)
- result.intVal = str[1].int64
-
- elif str.contains(re"""^"[[:ascii:]]+"$"""): # char *
- result = newStrNode(nkStrLit, str[1 .. ^2])
-
- else:
- decho "Macro AST:"
- decho str
- decho nimState.gState.getCCodeAst(str)
- let
- str =
- if expression: gState.getNimExpression(str)
- else: str
- result = gState.parseString(str)
-
- if result.isNil:
- result = newNode(nkNilLit)
+proc getLit*(nimState: NimState, str: string, expression = false): PNode =
+ result = nimState.codeToNode(str)
proc getOverrideOrSkip(gState: State, node: TSNode, origname: string, kind: NimSymKind): PNode =
# Check if symbol `origname` of `kind` and `origname` has any cOverride defined
@@ -181,11 +120,9 @@ proc newConstDef(gState: State, node: TSNode, fname = "", fval = ""): PNode =
if name.Bl:
# Name skipped or overridden since blank
- result = gState.getOverrideOrSkip(node, origname, nskConst)
- elif valident.kind in {nkCharLit .. nkStrLit} or
- (valident.kind == nkStmtList and valident.len > 0 and
- valident[0].kind in {nkCharLit .. nkStrLit}):
- if gState.addNewIdentifer(name):
+ result = nimState.getOverrideOrSkip(node, origname, nskConst)
+ elif valident.kind != nkNilLit:
+ if nimState.addNewIdentifer(name):
# const X* = Y
#
# nkConstDef(
diff --git a/nimterop/exprparser.nim b/nimterop/exprparser.nim
new file mode 100644
index 0000000..a4be5d0
--- /dev/null
+++ b/nimterop/exprparser.nim
@@ -0,0 +1,245 @@
+import strformat, strutils, macros
+
+import regex
+
+import compiler/[ast, renderer]
+
+import "."/treesitter/[api, c, cpp]
+
+import "."/[globals, getters]
+
+type
+ ExprParser* = ref object
+ state*: NimState
+ code*: string
+
+proc newExprParser*(state: NimState, code: string): ExprParser =
+ ExprParser(state: state, code: code)
+
+template decho(msg: varargs[string, `$`]) =
+ if exprParser.state.gState.debug:
+ let nimState {.inject.} = exprParser.state
+ necho "# " & join(msg, "")
+
+template val*(node: TSNode): string =
+ exprParser.code.getNodeVal(node)
+
+proc mode*(exprParser: ExprParser): string =
+ exprParser.state.gState.mode
+
+template withCodeAst(exprParser: ExprParser, body: untyped): untyped =
+ var parser = tsParserNew()
+ defer:
+ parser.tsParserDelete()
+
+ doAssert exprParser.code.nBl, "Empty code"
+ if exprParser.mode == "c":
+ doAssert parser.tsParserSetLanguage(treeSitterC()), "Failed to load C parser"
+ elif exprParser.mode == "cpp":
+ doAssert parser.tsParserSetLanguage(treeSitterCpp()), "Failed to load C++ parser"
+ else:
+ doAssert false, &"Invalid parser {exprParser.mode}"
+
+ var
+ tree = parser.tsParserParseString(nil, exprParser.code.cstring, exprParser.code.len.uint32)
+ root {.inject.} = tree.tsTreeRootNode()
+
+ body
+
+ defer:
+ tree.tsTreeDelete()
+
+
+proc getNumNode(number, suffix: string): PNode {.inline.} =
+ result = newNode(nkNilLit)
+ if number.contains("."):
+ let floatSuffix = number[result.len-1]
+ case floatSuffix
+ of 'l', 'L':
+ # TODO: handle long double (128 bits)
+ # result = newNode(nkFloat128Lit)
+ result = newFloatNode(nkFloat64Lit, parseFloat(number[0 ..< number.len - 1]))
+ of 'f', 'F':
+ result = newFloatNode(nkFloat64Lit, parseFloat(number[0 ..< number.len - 1]))
+ else:
+ discard
+ return
+
+ case suffix
+ of "u", "U":
+ result = newNode(nkUintLit)
+ of "l", "L":
+ result = newNode(nkInt32Lit)
+ of "ul", "UL":
+ result = newNode(nkUint32Lit)
+ of "ll", "LL":
+ result = newNode(nkInt64Lit)
+ of "ull", "ULL":
+ result = newNode(nkUint64Lit)
+ else:
+ result = newNode(nkIntLit)
+
+ if number.contains(re"0[xX]"):
+ result.intVal = parseHexInt(number)
+ result.flags = {nfBase16}
+ elif number.contains(re"0[bB]"):
+ result.intVal = parseBinInt(number)
+ result.flags = {nfBase2}
+ elif number.contains(re"0[oO]"):
+ result.intVal = parseOctInt(number)
+ result.flags = {nfBase8}
+ else:
+ result.intVal = parseInt(number)
+
+proc processNumberLiteral*(exprParser: ExprParser, node: TSNode): PNode =
+ result = newNode(nkNilLit)
+ let nodeVal = node.val
+
+ var match: RegexMatch
+ const reg = re"(\-)?(0\d+|0[xX][0-9a-fA-F]+|0[bB][01]+|\d+\.?\d*[fFlL]?|\d*\.?\d+[fFlL]?|\d+)([ulUL]*)"
+ let found = nodeVal.find(reg, match)
+ if found:
+ let
+ prefix = if match.group(0).len > 0: nodeVal[match.group(0)[0]] else: ""
+ number = nodeVal[match.group(1)[0]]
+ suffix = nodeVal[match.group(2)[0]]
+
+ result = getNumNode(number, suffix)
+
+ if result.kind != nkNilLit and prefix == "-":
+ result = nkPrefix.newTree(
+ exprParser.state.getIdent("-"),
+ result
+ )
+
+proc processCharacterLiteral*(exprParser: ExprParser, node: TSNode): PNode =
+ result = newNode(nkCharLit)
+ result.intVal = node.val[1].int64
+
+proc processStringLiteral*(exprParser: ExprParser, node: TSNode): PNode =
+ let nodeVal = node.val
+ result = newStrNode(nkStrLit, nodeVal[1 ..< nodeVal.len - 1])
+
+proc processTSNode*(exprParser: ExprParser, node: TSNode): PNode
+
+proc processShiftExpression*(exprParser: ExprParser, node: TSNode): PNode =
+ result = newNode(nkInfix)
+ let
+ left = node[0]
+ right = node[1]
+ var shiftSym = exprParser.code[left.tsNodeEndByte() ..< right.tsNodeStartByte()].strip()
+
+ case shiftSym
+ of "<<":
+ result.add exprParser.state.getIdent("shl")
+ of ">>":
+ result.add exprParser.state.getIdent("shr")
+ else:
+ discard
+
+ result.add exprParser.processTSNode(left)
+ result.add exprParser.processTSNode(right)
+
+proc processParenthesizedExpr*(exprParser: ExprParser, node: TSNode): PNode =
+ result = newNode(nkPar)
+ for i in 0 ..< node.len():
+ result.add(exprParser.processTSNode(node[i]))
+
+proc processLogicalExpression*(exprParser: ExprParser, node: TSNode): PNode =
+ result = newNode(nkPar)
+ let child = node[0]
+ var nimSym = ""
+
+ var binarySym = exprParser.code[node.tsNodeStartByte() ..< child.tsNodeStartByte()].strip()
+ decho "LOG SYM: ", binarySym
+
+ case binarySym
+ of "!":
+ nimSym = "not"
+ else:
+ return newNode(nkNilLit)
+
+ decho "LOG CHILD: ", child.val, ", nim: ", nimSym
+ result.add nkPrefix.newTree(
+ exprParser.state.getIdent(nimSym),
+ exprParser.processTSNode(child)
+ )
+
+proc processBitwiseExpression*(exprParser: ExprParser, node: TSNode): PNode =
+ if node.len() > 1:
+ result = newNode(nkInfix)
+ let left = node[0]
+ let right = node[1]
+ var nimSym = ""
+
+ var binarySym = exprParser.code[left.tsNodeEndByte() ..< right.tsNodeStartByte()].strip()
+ decho "# BIN SYM: ", binarySym
+
+ case binarySym
+ of "|", "||":
+ nimSym = "or"
+ of "&", "&&":
+ nimSym = "and"
+ of "^":
+ nimSym = "xor"
+ else:
+ return newNode(nkNilLit)
+
+ result.add exprParser.state.getIdent(nimSym)
+ result.add exprParser.processTSNode(left)
+ result.add exprParser.processTSNode(right)
+
+ elif node.len() == 1:
+ result = newNode(nkPar)
+ let child = node[0]
+ var nimSym = ""
+
+ var binarySym = exprParser.code[node.tsNodeStartByte() ..< child.tsNodeStartByte()].strip()
+ decho "# BIN SYM: ", binarySym
+
+ case binarySym
+ of "~":
+ nimSym = "not"
+ else:
+ return newNode(nkNilLit)
+
+ result.add nkPrefix.newTree(
+ exprParser.state.getIdent(nimSym),
+ exprParser.processTSNode(child)
+ )
+
+proc processTSNode*(exprParser: ExprParser, node: TSNode): PNode =
+ result = newNode(nkNilLit)
+ decho "# NODE: ", node.getName(), ", VAL: ", node.val
+ case node.getName()
+ of "number_literal":
+ result = exprParser.processNumberLiteral(node)
+ of "string_literal":
+ result = exprParser.processStringLiteral(node)
+ of "char_literal":
+ result = exprParser.processCharacterLiteral(node)
+ of "expression_statement", "ERROR", "translation_unit":
+ # This may be wrong. What can be in an expression?
+ result = exprParser.processTSNode(node[0])
+ of "parenthesized_expression":
+ result = exprParser.processParenthesizedExpr(node)
+ of "bitwise_expression":
+ result = exprParser.processBitwiseExpression(node)
+ of "shift_expression":
+ result = exprParser.processShiftExpression(node)
+ of "logical_expression":
+ result = exprParser.processLogicalExpression(node)
+ of "identifier":
+ var ident = node.val
+ if ident != "_":
+ ident = exprParser.state.getIdentifier(ident, nskConst)
+ result = exprParser.state.getIdent(ident)
+ else:
+ result = newNode(nkNilLit)
+
+ decho "# NODERES: ", result
+
+proc codeToNode*(state: NimState, code: string): PNode =
+ let exprParser = newExprParser(state, code)
+ withCodeAst(exprParser):
+ result = exprParser.processTSNode(root) \ No newline at end of file
diff --git a/nimterop/getters.nim b/nimterop/getters.nim
index 4ffb5d7..b96ae70 100644
--- a/nimterop/getters.nim
+++ b/nimterop/getters.nim
@@ -221,7 +221,7 @@ proc len*(node: TSNode): int =
result = node.tsNodeNamedChildCount().int
proc `[]`*(node: TSNode, i: SomeInteger): TSNode =
- if i < node.len:
+ if i < type(i)(node.len()):
result = node.tsNodeNamedChild(i.uint32)
proc getName*(node: TSNode): string {.inline.} =