Add preliminary expression parsing
This commit is contained in:
parent
80018f43cf
commit
879c7e3c78
3 changed files with 253 additions and 71 deletions
|
|
@ -1,37 +1,10 @@
|
||||||
import macros, os, sequtils, sets, strformat, strutils, tables, times
|
import macros, os, sequtils, sets, strformat, strutils, tables, times
|
||||||
|
|
||||||
import regex
|
|
||||||
|
|
||||||
import compiler/[ast, idents, lineinfos, modulegraphs, msgs, options, parser, renderer]
|
import compiler/[ast, idents, lineinfos, modulegraphs, msgs, options, parser, renderer]
|
||||||
|
|
||||||
import "."/treesitter/[api, c, cpp]
|
import "."/treesitter/api
|
||||||
|
|
||||||
import "."/[globals, getters]
|
import "."/[globals, getters, exprparser]
|
||||||
|
|
||||||
proc getCCodeAst*(gState: State, code: string): string =
|
|
||||||
var parser = tsParserNew()
|
|
||||||
var code = code
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc getPtrType*(str: string): string =
|
proc getPtrType*(str: string): string =
|
||||||
result = case str:
|
result = case str:
|
||||||
|
|
@ -59,42 +32,8 @@ proc parseString(gState: State, str: string): PNode =
|
||||||
except:
|
except:
|
||||||
decho getCurrentExceptionMsg()
|
decho getCurrentExceptionMsg()
|
||||||
|
|
||||||
proc getLit*(gState: State, str: string, expression = false): PNode =
|
proc getLit*(nimState: NimState, str: string, expression = false): PNode =
|
||||||
# Used to convert #define literals into const and expressions
|
result = nimState.codeToNode(str)
|
||||||
# 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 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
|
||||||
|
|
@ -181,11 +120,9 @@ proc newConstDef(gState: State, node: TSNode, fname = "", fval = ""): PNode =
|
||||||
|
|
||||||
if name.Bl:
|
if name.Bl:
|
||||||
# Name skipped or overridden since blank
|
# Name skipped or overridden since blank
|
||||||
result = gState.getOverrideOrSkip(node, origname, nskConst)
|
result = nimState.getOverrideOrSkip(node, origname, nskConst)
|
||||||
elif valident.kind in {nkCharLit .. nkStrLit} or
|
elif valident.kind != nkNilLit:
|
||||||
(valident.kind == nkStmtList and valident.len > 0 and
|
if nimState.addNewIdentifer(name):
|
||||||
valident[0].kind in {nkCharLit .. nkStrLit}):
|
|
||||||
if gState.addNewIdentifer(name):
|
|
||||||
# const X* = Y
|
# const X* = Y
|
||||||
#
|
#
|
||||||
# nkConstDef(
|
# nkConstDef(
|
||||||
|
|
|
||||||
245
nimterop/exprparser.nim
Normal file
245
nimterop/exprparser.nim
Normal file
|
|
@ -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)
|
||||||
|
|
@ -221,7 +221,7 @@ proc len*(node: TSNode): int =
|
||||||
result = node.tsNodeNamedChildCount().int
|
result = node.tsNodeNamedChildCount().int
|
||||||
|
|
||||||
proc `[]`*(node: TSNode, i: SomeInteger): TSNode =
|
proc `[]`*(node: TSNode, i: SomeInteger): TSNode =
|
||||||
if i < node.len:
|
if i < type(i)(node.len()):
|
||||||
result = node.tsNodeNamedChild(i.uint32)
|
result = node.tsNodeNamedChild(i.uint32)
|
||||||
|
|
||||||
proc getName*(node: TSNode): string {.inline.} =
|
proc getName*(node: TSNode): string {.inline.} =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue