Update to include more expressions
This commit is contained in:
parent
d2daf22df4
commit
b51f0da6b2
6 changed files with 187 additions and 79 deletions
|
|
@ -1,10 +1,10 @@
|
|||
import macros, os, sequtils, sets, strformat, strutils, tables, times
|
||||
|
||||
import compiler/[ast, idents, lineinfos, modulegraphs, msgs, options, parser, renderer]
|
||||
import compiler/[ast, idents, lineinfos, modulegraphs, msgs, options, renderer]
|
||||
|
||||
import "."/treesitter/api
|
||||
|
||||
import "."/[globals, getters, exprparser]
|
||||
import "."/[globals, getters, exprparser, utils]
|
||||
|
||||
proc getPtrType*(str: string): string =
|
||||
result = case str:
|
||||
|
|
@ -17,21 +17,6 @@ proc getPtrType*(str: string): string =
|
|||
else:
|
||||
str
|
||||
|
||||
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(gState: State, 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, gState.identCache, gState.config, errorHandler = handleError
|
||||
)
|
||||
except:
|
||||
decho getCurrentExceptionMsg()
|
||||
|
||||
proc getLit*(nimState: NimState, str: string, expression = false): PNode =
|
||||
result = nimState.codeToNode(str)
|
||||
|
||||
|
|
@ -121,7 +106,7 @@ proc newConstDef(gState: State, node: TSNode, fname = "", fval = ""): PNode =
|
|||
if name.Bl:
|
||||
# Name skipped or overridden since blank
|
||||
result = nimState.getOverrideOrSkip(node, origname, nskConst)
|
||||
elif valident.kind != nkNilLit:
|
||||
elif valident.kind != nkNone:
|
||||
if nimState.addNewIdentifer(name):
|
||||
# const X* = Y
|
||||
#
|
||||
|
|
@ -179,7 +164,7 @@ proc addPragma(gState: State, node: TSNode, pragma: PNode, name: string, value:
|
|||
if value.isNil:
|
||||
pragma.add pident
|
||||
else:
|
||||
let
|
||||
var
|
||||
colExpr = newNode(nkExprColonExpr)
|
||||
colExpr.add pident
|
||||
colExpr.add value
|
||||
|
|
@ -1501,6 +1486,7 @@ proc addProc(gState: State, node, rnode: TSNode) =
|
|||
# Parameter list
|
||||
plist = node.anyChildInTree("parameter_list")
|
||||
|
||||
var
|
||||
procDef = newNode(nkProcDef)
|
||||
|
||||
# proc X(a1: Y, a2: Z): P {.pragma.}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import compiler/[ast, renderer]
|
|||
|
||||
import "."/treesitter/[api, c, cpp]
|
||||
|
||||
import "."/[globals, getters]
|
||||
import "."/[globals, getters, utils]
|
||||
|
||||
type
|
||||
ExprParser* = ref object
|
||||
|
|
@ -21,15 +21,16 @@ proc newExprParser*(state: NimState, code: string): ExprParser =
|
|||
template techo(msg: varargs[string, `$`]) =
|
||||
if exprParser.state.gState.debug:
|
||||
let nimState {.inject.} = exprParser.state
|
||||
necho "# " & join(msg, "").replace("\n", "\n# ")
|
||||
necho join(msg, "").getCommented
|
||||
|
||||
template val*(node: TSNode): string =
|
||||
template val(node: TSNode): string =
|
||||
exprParser.code.getNodeVal(node)
|
||||
|
||||
proc mode*(exprParser: ExprParser): string =
|
||||
proc mode(exprParser: ExprParser): string =
|
||||
exprParser.state.gState.mode
|
||||
|
||||
template withCodeAst(exprParser: ExprParser, body: untyped): untyped =
|
||||
## A simple template to inject the TSNode into a body of code
|
||||
var parser = tsParserNew()
|
||||
defer:
|
||||
parser.tsParserDelete()
|
||||
|
|
@ -51,9 +52,9 @@ template withCodeAst(exprParser: ExprParser, body: untyped): untyped =
|
|||
defer:
|
||||
tree.tsTreeDelete()
|
||||
|
||||
|
||||
proc getNumNode(number, suffix: string): PNode {.inline.} =
|
||||
result = newNode(nkNilLit)
|
||||
## Convert a C number to a Nim number PNode
|
||||
result = newNode(nkNone)
|
||||
if number.contains("."):
|
||||
let floatSuffix = number[result.len-1]
|
||||
try:
|
||||
|
|
@ -84,6 +85,8 @@ proc getNumNode(number, suffix: string): PNode {.inline.} =
|
|||
else:
|
||||
result = newNode(nkIntLit)
|
||||
|
||||
# I realize these regex are wasteful on performance, but
|
||||
# couldn't come up with a better idea.
|
||||
if number.contains(re"0[xX]"):
|
||||
result.intVal = parseHexInt(number)
|
||||
result.flags = {nfBase16}
|
||||
|
|
@ -97,7 +100,7 @@ proc getNumNode(number, suffix: string): PNode {.inline.} =
|
|||
result.intVal = parseInt(number)
|
||||
|
||||
proc processNumberLiteral*(exprParser: ExprParser, node: TSNode): PNode =
|
||||
result = newNode(nkNilLit)
|
||||
result = newNode(nkNone)
|
||||
let nodeVal = node.val
|
||||
|
||||
var match: RegexMatch
|
||||
|
|
@ -111,7 +114,7 @@ proc processNumberLiteral*(exprParser: ExprParser, node: TSNode): PNode =
|
|||
|
||||
result = getNumNode(number, suffix)
|
||||
|
||||
if result.kind != nkNilLit and prefix == "-":
|
||||
if result.kind != nkNone and prefix == "-":
|
||||
result = nkPrefix.newTree(
|
||||
exprParser.state.getIdent("-"),
|
||||
result
|
||||
|
|
@ -127,9 +130,9 @@ 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 processTSNode*(exprParser: ExprParser, node: TSNode, typeofNode: PNode = nil): PNode
|
||||
|
||||
proc processShiftExpression*(exprParser: ExprParser, node: TSNode): PNode =
|
||||
proc processShiftExpression*(exprParser: ExprParser, node: TSNode, typeofNode: PNode = nil): PNode =
|
||||
result = newNode(nkInfix)
|
||||
let
|
||||
left = node[0]
|
||||
|
|
@ -144,25 +147,29 @@ proc processShiftExpression*(exprParser: ExprParser, node: TSNode): PNode =
|
|||
else:
|
||||
raise newException(ExprParseError, &"Unsupported shift symbol \"{shiftSym}\"")
|
||||
|
||||
let
|
||||
leftNode = exprParser.processTSNode(left)
|
||||
rightNode = exprParser.processTSNode(right)
|
||||
let leftNode = exprParser.processTSNode(left, typeofNode)
|
||||
|
||||
var tnode = typeofNode
|
||||
if tnode.isNil:
|
||||
tnode = leftNode
|
||||
|
||||
let rightNode = exprParser.processTSNode(right, tnode)
|
||||
|
||||
result.add leftNode
|
||||
result.add nkCast.newTree(
|
||||
nkCall.newTree(
|
||||
exprParser.state.getIdent("typeof"),
|
||||
leftNode
|
||||
tnode
|
||||
),
|
||||
rightNode
|
||||
)
|
||||
|
||||
proc processParenthesizedExpr*(exprParser: ExprParser, node: TSNode): PNode =
|
||||
proc processParenthesizedExpr*(exprParser: ExprParser, node: TSNode, typeofNode: PNode = nil): PNode =
|
||||
result = newNode(nkPar)
|
||||
for i in 0 ..< node.len():
|
||||
result.add(exprParser.processTSNode(node[i]))
|
||||
result.add(exprParser.processTSNode(node[i], typeofNode))
|
||||
|
||||
proc processLogicalExpression*(exprParser: ExprParser, node: TSNode): PNode =
|
||||
proc processLogicalExpression*(exprParser: ExprParser, node: TSNode, typeofNode: PNode = nil): PNode =
|
||||
result = newNode(nkPar)
|
||||
let child = node[0]
|
||||
var nimSym = ""
|
||||
|
|
@ -179,14 +186,96 @@ proc processLogicalExpression*(exprParser: ExprParser, node: TSNode): PNode =
|
|||
techo "LOG CHILD: ", child.val, ", nim: ", nimSym
|
||||
result.add nkPrefix.newTree(
|
||||
exprParser.state.getIdent(nimSym),
|
||||
exprParser.processTSNode(child)
|
||||
exprParser.processTSNode(child, typeofNode)
|
||||
)
|
||||
|
||||
proc processBitwiseExpression*(exprParser: ExprParser, node: TSNode): PNode =
|
||||
proc processMathExpression(exprParser: ExprParser, node: TSNode, typeofNode: PNode = nil): PNode =
|
||||
if node.len > 1:
|
||||
# Node has left and right children ie: (2 + 7)
|
||||
var
|
||||
res = newNode(nkInfix)
|
||||
let
|
||||
left = node[0]
|
||||
right = node[1]
|
||||
|
||||
let mathSym = exprParser.code[left.tsNodeEndByte() ..< right.tsNodeStartByte()].strip()
|
||||
techo "MATH SYM: ", mathSym
|
||||
|
||||
res.add exprParser.state.getIdent(mathSym)
|
||||
let leftNode = exprParser.processTSNode(left, typeofNode)
|
||||
|
||||
var tnode = typeofNode
|
||||
if tnode.isNil:
|
||||
tnode = leftNode
|
||||
|
||||
let rightNode = exprParser.processTSNode(right, tnode)
|
||||
|
||||
res.add leftNode
|
||||
# res.add rightNode
|
||||
res.add nkCast.newTree(
|
||||
nkCall.newTree(
|
||||
exprParser.state.getIdent("typeof"),
|
||||
tnode
|
||||
),
|
||||
rightNode
|
||||
)
|
||||
|
||||
# Make sure the statement is of the same type as the left
|
||||
# hand argument, since some expressions return a differing
|
||||
# type than the input types (2/3 == float)
|
||||
result = nkCall.newTree(
|
||||
nkCall.newTree(
|
||||
exprParser.state.getIdent("typeof"),
|
||||
tnode
|
||||
),
|
||||
res
|
||||
)
|
||||
|
||||
elif node.len() == 1:
|
||||
# Node has only one child, ie -(20 + 7)
|
||||
result = newNode(nkPar)
|
||||
let child = node[0]
|
||||
var nimSym = ""
|
||||
|
||||
let unarySym = exprParser.code[node.tsNodeStartByte() ..< child.tsNodeStartByte()].strip()
|
||||
techo "MATH SYM: ", unarySym
|
||||
|
||||
case unarySym
|
||||
of "+":
|
||||
nimSym = "+"
|
||||
of "-":
|
||||
# Special case. The minus symbol must be in front of an integer,
|
||||
# so we have to make a gental cast here to coerce it to one.
|
||||
# Might be bad because we are overwriting the type
|
||||
# There's probably a better way of doing this
|
||||
result.add nkPrefix.newTree(
|
||||
exprParser.state.getIdent(unarySym),
|
||||
nkPar.newTree(
|
||||
nkCall.newTree(
|
||||
exprParser.state.getIdent("int64"),
|
||||
exprParser.processTSNode(child, typeofNode)
|
||||
)
|
||||
)
|
||||
)
|
||||
return
|
||||
else:
|
||||
raise newException(ExprParseError, &"Unsupported unary symbol \"{unarySym}\"")
|
||||
|
||||
result.add nkPrefix.newTree(
|
||||
exprParser.state.getIdent(nimSym),
|
||||
exprParser.processTSNode(child, typeofNode)
|
||||
)
|
||||
else:
|
||||
raise newException(ExprParseError, &"Invalid bitwise_expression \"{node.val}\"")
|
||||
|
||||
proc processBitwiseExpression(exprParser: ExprParser, node: TSNode, typeofNode: PNode = nil): PNode =
|
||||
if node.len() > 1:
|
||||
result = newNode(nkInfix)
|
||||
let left = node[0]
|
||||
let right = node[1]
|
||||
|
||||
let
|
||||
left = node[0]
|
||||
right = node[1]
|
||||
|
||||
var nimSym = ""
|
||||
|
||||
var binarySym = exprParser.code[left.tsNodeEndByte() ..< right.tsNodeStartByte()].strip()
|
||||
|
|
@ -199,21 +288,23 @@ proc processBitwiseExpression*(exprParser: ExprParser, node: TSNode): PNode =
|
|||
nimSym = "and"
|
||||
of "^":
|
||||
nimSym = "xor"
|
||||
of "+", "-", "*", "/":
|
||||
nimSym = binarySym
|
||||
else:
|
||||
raise newException(ExprParseError, &"Unsupported binary symbol \"{binarySym}\"")
|
||||
|
||||
result.add exprParser.state.getIdent(nimSym)
|
||||
let
|
||||
leftNode = exprParser.processTSNode(left)
|
||||
rightNode = exprParser.processTSNode(right)
|
||||
let leftNode = exprParser.processTSNode(left, typeofNode)
|
||||
|
||||
var tnode = typeofNode
|
||||
if tnode.isNil:
|
||||
tnode = leftNode
|
||||
|
||||
let rightNode = exprParser.processTSNode(right, tnode)
|
||||
|
||||
result.add leftNode
|
||||
result.add nkCast.newTree(
|
||||
result.add nkCall.newTree(
|
||||
nkCall.newTree(
|
||||
exprParser.state.getIdent("typeof"),
|
||||
leftNode
|
||||
tnode
|
||||
),
|
||||
rightNode
|
||||
)
|
||||
|
|
@ -223,24 +314,26 @@ proc processBitwiseExpression*(exprParser: ExprParser, node: TSNode): PNode =
|
|||
let child = node[0]
|
||||
var nimSym = ""
|
||||
|
||||
var binarySym = exprParser.code[node.tsNodeStartByte() ..< child.tsNodeStartByte()].strip()
|
||||
techo "BIN SYM: ", binarySym
|
||||
var unarySym = exprParser.code[node.tsNodeStartByte() ..< child.tsNodeStartByte()].strip()
|
||||
techo "BIN SYM: ", unarySym
|
||||
|
||||
case binarySym
|
||||
case unarySym
|
||||
of "~":
|
||||
nimSym = "not"
|
||||
else:
|
||||
raise newException(ExprParseError, &"Unsupported unary symbol \"{binarySym}\"")
|
||||
raise newException(ExprParseError, &"Unsupported unary symbol \"{unarySym}\"")
|
||||
|
||||
result.add nkPrefix.newTree(
|
||||
exprParser.state.getIdent(nimSym),
|
||||
exprParser.processTSNode(child)
|
||||
exprParser.processTSNode(child, typeofNode)
|
||||
)
|
||||
else:
|
||||
raise newException(ExprParseError, &"Invalid bitwise_expression \"{node.val}\"")
|
||||
|
||||
proc processTSNode*(exprParser: ExprParser, node: TSNode): PNode =
|
||||
result = newNode(nkNilLit)
|
||||
proc processTSNode(exprParser: ExprParser, node: TSNode, typeofNode: PNode = nil): PNode =
|
||||
## Handle all of the types of expressions here. This proc gets called recursively
|
||||
## in the processX procs and will drill down to sub nodes.
|
||||
result = newNode(nkNone)
|
||||
let nodeName = node.getName()
|
||||
techo "NODE: ", nodeName, ", VAL: ", node.val
|
||||
case nodeName
|
||||
|
|
@ -253,36 +346,47 @@ proc processTSNode*(exprParser: ExprParser, node: TSNode): PNode =
|
|||
of "expression_statement", "ERROR", "translation_unit":
|
||||
# This may be wrong. What can be in an expression?
|
||||
if node.len > 0:
|
||||
result = exprParser.processTSNode(node[0])
|
||||
result = exprParser.processTSNode(node[0], typeofNode)
|
||||
else:
|
||||
raise newException(ExprParseError, &"Node type \"{nodeName}\" has no children")
|
||||
|
||||
of "parenthesized_expression":
|
||||
result = exprParser.processParenthesizedExpr(node)
|
||||
of "bitwise_expression", "math_expression":
|
||||
result = exprParser.processBitwiseExpression(node)
|
||||
result = exprParser.processParenthesizedExpr(node, typeofNode)
|
||||
of "bitwise_expression":
|
||||
result = exprParser.processBitwiseExpression(node, typeofNode)
|
||||
of "math_expression":
|
||||
result = exprParser.processMathExpression(node, typeofNode)
|
||||
of "shift_expression":
|
||||
result = exprParser.processShiftExpression(node)
|
||||
result = exprParser.processShiftExpression(node, typeofNode)
|
||||
of "logical_expression":
|
||||
result = exprParser.processLogicalExpression(node)
|
||||
result = exprParser.processLogicalExpression(node, typeofNode)
|
||||
# Why are these node types named true/false?
|
||||
of "true", "false":
|
||||
result = exprParser.state.parseString(node.val)
|
||||
of "identifier":
|
||||
var ident = node.val
|
||||
if ident != "_":
|
||||
# Process the identifier through cPlugin
|
||||
ident = exprParser.state.getIdentifier(ident, nskConst)
|
||||
result = exprParser.state.getIdent(ident)
|
||||
techo ident
|
||||
if ident != "":
|
||||
result = exprParser.state.getIdent(ident)
|
||||
if result.kind == nkNone:
|
||||
raise newException(ExprParseError, &"Could not get identifier \"{ident}\"")
|
||||
else:
|
||||
raise newException(ExprParseError, &"Unsupported node type \"{nodeName}\" for node \"{node.val}\"")
|
||||
|
||||
techo "NODERES: ", result
|
||||
techo "NODE RES: ", result
|
||||
|
||||
proc codeToNode*(state: NimState, code: string): PNode =
|
||||
let exprParser = newExprParser(state, code)
|
||||
## Convert the C string to a nim PNode tree
|
||||
result = newNode(nkNone)
|
||||
try:
|
||||
let exprParser = newExprParser(state, code)
|
||||
withCodeAst(exprParser):
|
||||
result = exprParser.processTSNode(root)
|
||||
except ExprParseError as e:
|
||||
techo e.msg
|
||||
result = newNode(nkNilLit)
|
||||
echo e.msg.getCommented
|
||||
result = newNode(nkNone)
|
||||
except Exception as e:
|
||||
techo e.msg
|
||||
result = newNode(nkNilLit)
|
||||
echo e.msg.getCommented
|
||||
result = newNode(nkNone)
|
||||
|
|
@ -399,7 +399,7 @@ proc printLisp*(code: var string, root: TSNode): string =
|
|||
else:
|
||||
break
|
||||
|
||||
if node.tsNodeNamedChildCount() != 0:
|
||||
if node.len() != 0:
|
||||
result &= "\n"
|
||||
nextnode = node.tsNodeNamedChild(0)
|
||||
depth += 1
|
||||
|
|
@ -459,15 +459,19 @@ proc printTree*(gState: State, pnode: PNode, offset = ""): string =
|
|||
if offset.len == 0:
|
||||
result &= "\n"
|
||||
|
||||
proc printDebug*(gState: State, node: TSNode) =
|
||||
if gState.debug:
|
||||
gecho ("Input => " & gState.getNodeVal(node)).getCommented() & "\n" &
|
||||
gState.printLisp(node).getCommented()
|
||||
proc printDebug*(nimState: NimState, node: TSNode) =
|
||||
discard
|
||||
# This causes random segfaults for some reason on macOS Catalina
|
||||
if nimState.gState.debug:
|
||||
necho ("Input => " & nimState.getNodeVal(node)).getCommented()
|
||||
necho nimState.gState.printLisp(node).getCommented()
|
||||
|
||||
proc printDebug*(gState: State, pnode: PNode) =
|
||||
if gState.debug:
|
||||
gecho ("Output => " & $pnode).getCommented() & "\n" &
|
||||
gState.printTree(pnode)
|
||||
proc printDebug*(nimState: NimState, pnode: PNode) =
|
||||
discard
|
||||
# This causes random segfaults for some reason on macOS Catalina
|
||||
if nimState.gState.debug and pnode.kind != nkNone:
|
||||
necho ("Output => " & $pnode).getCommented()
|
||||
necho nimState.printTree(pnode)
|
||||
|
||||
# Compiler shortcuts
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ when not declared(CIMPORT):
|
|||
export gAtoms, gExpressions, gEnumVals, Kind, Ast, AstTable, State, nBl, Bl
|
||||
|
||||
# Redirect output to file when required
|
||||
template gecho*(args: string) {.dirty.} =
|
||||
template gecho*(args: string) =
|
||||
if gState.outputHandle.isNil:
|
||||
echo args
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -17,6 +17,12 @@ extern "C" {
|
|||
#define SHL1 (1u << 1)
|
||||
#define SHL2 (1u << 2)
|
||||
#define SHL3 (1u << 3)
|
||||
#define COERCE 645635634896ull + -35436
|
||||
#define COERCE2 645635634896 + -35436
|
||||
#define BINEXPR ~(-(1u << !-1)) ^ (10 >> 1)
|
||||
#define BOOL true
|
||||
#define MATHEXPR (1 + 2/3*20 - 100)
|
||||
#define ANDEXPR (100 & 11000)
|
||||
|
||||
#define ALLSHL (SHL1 | SHL2 | SHL3)
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,14 @@ assert ULLEXPR == (1234.uint64 shl 3)
|
|||
assert LEXPR == (1234.int32 shl 4)
|
||||
assert LLEXPR == (1234.int64 shl 5)
|
||||
|
||||
assert COERCE == 645635599460'u64
|
||||
assert COERCE2 == 645635599460'i64
|
||||
|
||||
assert BINEXPR == 5
|
||||
assert BOOL == true
|
||||
assert MATHEXPR == -99
|
||||
assert ANDEXPR == 96
|
||||
|
||||
assert SHL1 == (1.uint shl 1)
|
||||
assert SHL2 == (1.uint shl 2)
|
||||
assert SHL3 == (1.uint shl 3)
|
||||
|
|
@ -283,7 +291,7 @@ var a21p: A21p
|
|||
a21p = addr a20
|
||||
|
||||
assert A22 is object
|
||||
testFields(A22, "f1|f2!ptr ptr cint|array[123 + cast[typeof(123)](132), ptr cint]")
|
||||
testFields(A22, "f1|f2!ptr ptr cint|array[typeof(123)(123 + cast[typeof(123)](132)), ptr cint]")
|
||||
checkPragmas(A22, pHeaderBy, istype = false)
|
||||
var a22: A22
|
||||
a22.f1 = addr a15.a2[0]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue