Add string and char support

This commit is contained in:
Joey Yakimowich-Payne 2020-04-19 19:18:04 -06:00
commit 1f56983cb2
4 changed files with 87 additions and 11 deletions

View file

@ -164,7 +164,7 @@ proc addPragma(gState: State, node: TSNode, pragma: PNode, name: string, value:
if value.isNil:
pragma.add pident
else:
var
let
colExpr = newNode(nkExprColonExpr)
colExpr.add pident
colExpr.add value
@ -1386,7 +1386,7 @@ proc addEnum(gState: State, node: TSNode) =
if en.len > 1 and en[1].getName() in gEnumVals:
# Explicit value
fval = "(" & gState.getNimExpression(gState.getNodeVal(en[1]), name) & ")." & name
fval = "(" & $gState.codeToNode(gState.getNodeVal(en[1]), name) & ")." & name
# Cannot use newConstDef() since parseString(fval) adds backticks to and/or
gState.constSection.add gState.parseString(&"const {fname}* = {fval}")[0][0]

View file

@ -1,4 +1,4 @@
import strformat, strutils, macros
import strformat, strutils, macros, sets
import regex
@ -12,11 +12,12 @@ type
ExprParser* = ref object
state*: NimState
code*: string
name*: string
ExprParseError* = object of CatchableError
proc newExprParser*(state: NimState, code: string): ExprParser =
ExprParser(state: state, code: code)
proc newExprParser*(state: NimState, code: string, name = ""): ExprParser =
ExprParser(state: state, code: code, name: name)
template techo(msg: varargs[string, `$`]) =
if exprParser.state.gState.debug:
@ -38,6 +39,8 @@ proc getIdent(exprParser: ExprParser, identName: string, kind = nskConst, parent
if ident != "_":
# Process the identifier through cPlugin
ident = exprParser.state.getIdentifier(ident, kind, parent)
if exprParser.name.nBl and ident in exprParser.state.constIdentifiers:
ident = ident & "." & exprParser.name
if ident != "":
result = exprParser.state.getIdent(ident)
@ -70,6 +73,55 @@ template withCodeAst(exprParser: ExprParser, body: untyped): untyped =
defer:
tree.tsTreeDelete()
proc parseChar(charStr: string): uint8 {.inline.} =
if charStr.len == 1:
return charStr[0].uint8
# Handle octal, hex, unicode?
if charStr.startsWith("\\x"):
result = parseHexInt(charStr.replace("\\x", "0x")).uint8
elif charStr.len == 4: # Octal
result = parseOctInt("0o" & charStr[1 ..< charStr.len]).uint8
if result == 0:
case charStr
of "\\0":
result = ord('\0')
of "\\a":
result = 0x07
of "\\b":
result = 0x08
of "\\e":
result = 0x1B
of "\\f":
result = 0x0C
of "\\n":
result = '\n'.uint8
of "\\r":
result = 0x0D
of "\\t":
result = 0x09
of "\\v":
result = 0x0B
of "\\\\":
result = 0x5C
of "\\'":
result = '\''.uint8
of "\\\"":
result = '\"'.uint8
of "\\?":
result = 0x3F
else:
discard
if result > uint8.high:
result = uint8.high
proc getCharLit(charStr: string): PNode {.inline.} =
result = newNode(nkCharLit)
result.intVal = parseChar(charStr).int64
proc getNumNode(number, suffix: string): PNode {.inline.} =
## Convert a C number to a Nim number PNode
result = newNode(nkNone)
@ -142,12 +194,24 @@ proc processNumberLiteral*(exprParser: ExprParser, node: TSNode): PNode =
raise newException(ExprParseError, &"Could not find a number in number_literal: \"{nodeVal}\"")
proc processCharacterLiteral*(exprParser: ExprParser, node: TSNode): PNode =
result = newNode(nkCharLit)
result.intVal = node.val[1].int64
let val = node.val
result = getCharLit(val[1 ..< val.len - 1])
proc processStringLiteral*(exprParser: ExprParser, node: TSNode): PNode =
let nodeVal = node.val
result = newStrNode(nkStrLit, nodeVal[1 ..< nodeVal.len - 1])
let
nodeVal = node.val
strVal = nodeVal[1 ..< nodeVal.len - 1]
const
str = "(\\\\x[[:xdigit:]]{2}|\\\\\\d{3}|\\\\0|\\\\a|\\\\b|\\\\e|\\\\f|\\\\n|\\\\r|\\\\t|\\\\v|\\\\\\\\|\\\\'|\\\\\"|[[:ascii:]])"
reg = re(str)
# Convert the c string escape sequences/etc to Nim chars
var nimStr = newStringOfCap(nodeVal.len)
for m in strVal.findAll(reg):
nimStr.add(parseChar(strVal[m.group(0)[0]]).chr)
result = newStrNode(nkStrLit, nimStr)
proc processTSNode*(exprParser: ExprParser, node: TSNode, typeofNode: var PNode): PNode
@ -415,13 +479,13 @@ proc processTSNode(exprParser: ExprParser, node: TSNode, typeofNode: var PNode):
techo "NODE RESULT: ", result
proc codeToNode*(state: NimState, code: string): PNode =
proc codeToNode*(state: NimState, code: string, name = ""): PNode =
## Convert the C string to a nim PNode tree
result = newNode(nkNone)
# This is used for keeping track of the type of the first
# symbol
var tnode: PNode = nil
let exprParser = newExprParser(state, code)
let exprParser = newExprParser(state, code, name)
try:
withCodeAst(exprParser):
result = exprParser.processTSNode(root, tnode)

View file

@ -23,6 +23,12 @@ extern "C" {
#define BOOL true
#define MATHEXPR (1 + 2/3*20 - 100)
#define ANDEXPR (100 & 11000)
#define CASTEXPR (char) 34
#define NULLCHAR '\0'
#define OCTCHAR '\012'
#define HEXCHAR '\xFE'
#define TRICKYSTR "\x4E\034\nfoo\0\'\"\r\v\a\b\e\f\t\\\?bar"
#define ALLSHL (SHL1 | SHL2 | SHL3)

View file

@ -118,6 +118,12 @@ assert BINEXPR == 5
assert BOOL == true
assert MATHEXPR == -99
assert ANDEXPR == 96
assert CASTEXPR == 34.chr
assert TRICKYSTR == "N\x1C\nfoo\x00\'\"\c\v\a\b\e\f\t\\\\?bar"
assert NULLCHAR == '\0'
assert OCTCHAR == '\n'
assert HEXCHAR.int == 0xFE
assert SHL1 == (1.uint shl 1)
assert SHL2 == (1.uint shl 2)