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 regex
|
||||
|
||||
import compiler/[ast, idents, lineinfos, modulegraphs, msgs, options, parser, renderer]
|
||||
|
||||
import "."/treesitter/[api, c, cpp]
|
||||
import "."/treesitter/api
|
||||
|
||||
import "."/[globals, getters]
|
||||
|
||||
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)
|
||||
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(
|
||||
|
|
|
|||
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
|
||||
|
||||
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.} =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue