diff options
| author | Joey Yakimowich-Payne <jyapayne@gmail.com> | 2020-04-16 20:49:06 -0600 |
|---|---|---|
| committer | Joey Yakimowich-Payne <jyapayne@gmail.com> | 2020-04-23 17:30:28 -0600 |
| commit | 879c7e3c784b3debce068a93e7f9ee116eb7bc21 (patch) | |
| tree | 8c0c2ef2742335369db091cfde95e1e23ac12708 | |
| parent | 80018f43cf35214e95c4fa777f65bb756be1db24 (diff) | |
| download | nimterop-879c7e3c784b3debce068a93e7f9ee116eb7bc21.tar.gz nimterop-879c7e3c784b3debce068a93e7f9ee116eb7bc21.zip | |
Add preliminary expression parsing
| -rw-r--r-- | nimterop/ast2.nim | 77 | ||||
| -rw-r--r-- | nimterop/exprparser.nim | 245 | ||||
| -rw-r--r-- | nimterop/getters.nim | 2 |
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.} = |
