Added double-precision floating point numbers and integers. Implemented the 4 fundamental operations, modulo division and exponentiation

This commit is contained in:
nocturn9x 2020-08-10 10:48:21 +02:00
parent fe07ed4f49
commit e4791ef027
10 changed files with 115 additions and 77 deletions

View File

@ -1,5 +1,4 @@
import lexer
import vm
import strformat
import meta/chunk
import meta/tokenobject
@ -120,12 +119,12 @@ proc parsePrecedence(self: Compiler, precedence: Precedence) =
discard self.parser.advance()
var prefixRule = getRule(self.parser.previous.kind).prefix
if prefixRule == nil:
self.parser.parseError(self.parser.peek, "Expecting expression")
self.parser.parseError(self.parser.previous, "Expecting expression")
return
self.prefixRule()
var precedence = int precedence
while precedence <= (int getRule(self.parser.peek.kind).precedence):
var infixRule = getRule(self.parser.previous().kind).infix
var infixRule = getRule(self.parser.advance.kind).infix
self.infixRule()
@ -146,9 +145,14 @@ proc binary(self: Compiler) =
self.emitByte(OP_DIVIDE)
of STAR:
self.emitByte(OP_MULTIPLY)
of MOD:
self.emitByte(OP_MOD)
of POW:
self.emitByte(OP_POW)
else:
return
proc unary(self: Compiler) =
var operator = self.parser.previous().kind
self.parsePrecedence(PREC_UNARY)
@ -162,10 +166,18 @@ proc str(self: Compiler) =
return
proc bracket(self: Compiler) =
return
proc literal(self: Compiler) =
return
proc strVal(self: Compiler) =
return
proc number(self: Compiler) =
var value = self.parser.previous().literal
self.emitConstant(value)
@ -177,50 +189,55 @@ proc grouping(self: Compiler) =
var rules: array[TokenType, ParseRule] = [
makeRule(grouping, nil, PREC_NONE), # LP
makeRule(nil, nil, PREC_NONE), # RP
makeRule(nil, nil, PREC_NONE), # LB
makeRule(nil, nil, PREC_NONE), # RB
makeRule(nil, nil, PREC_NONE), # COMMA
makeRule(nil, nil, PREC_NONE), # DOT
makeRule(unary, binary, PREC_TERM), # MINUS
makeRule(nil, binary, PREC_TERM), # PLUS
makeRule(nil, nil, PREC_NONE), # SEMICOLON
makeRule(nil, binary, PREC_FACTOR), # SLASH
makeRule(nil, binary, PREC_FACTOR), # STAR
makeRule(unary, nil, PREC_NONE), # NEG
makeRule(nil, binary, PREC_EQUALITY), # NE
makeRule(nil, nil, PREC_NONE), # EQ
makeRule(nil, binary, PREC_COMPARISON), # DEQ
makeRule(nil, binary, PREC_COMPARISON), # GT
makeRule(nil, binary, PREC_COMPARISON), # GE
makeRule(nil, binary, PREC_COMPARISON), # LT
makeRule(nil, binary, PREC_COMPARISON), # LE
makeRule(nil, nil, PREC_NONE), # ID
makeRule(str, nil, PREC_NONE), # STR
makeRule(number, nil, PREC_NONE), # INT
makeRule(number, nil, PREC_NONE), # FLOAT
makeRule(nil, nil, PREC_NONE), # AND
makeRule(nil, nil, PREC_NONE), # CLASS
makeRule(nil, nil, PREC_NONE), # ELSE
makeRule(literal, nil, PREC_NONE), # FALSE
makeRule(nil, nil, PREC_NONE), # FOR
makeRule(nil, nil, PREC_NONE), # FUN
makeRule(nil, nil, PREC_NONE), # IF
makeRule(literal, nil, PREC_NONE), # NIL
makeRule(nil, nil, PREC_NONE), # OR
makeRule(nil, nil, PREC_NONE), # RETURN
makeRule(nil, nil, PREC_NONE), # SUPER
makeRule(nil, nil, PREC_NONE), # THIS
makeRule(literal, nil, PREC_NONE), # TRUE
makeRule(nil, nil, PREC_NONE), # VAR
makeRule(nil, nil, PREC_NONE), # WHILE
makeRule(nil, nil, PREC_NONE), # EOF
makeRule(nil, binary, PREC_TERM), # PLUS
makeRule(unary, binary, PREC_TERM), # MINUS
makeRule(nil, binary, PREC_FACTOR), # SLASH
makeRule(nil, binary, PREC_FACTOR), # STAR
makeRule(unary, nil, PREC_NONE), # NEG
makeRule(nil, binary, PREC_EQUALITY), # NE
makeRule(nil, nil, PREC_NONE), # EQ
makeRule(nil, binary, PREC_COMPARISON), # DEQ
makeRule(nil, binary, PREC_COMPARISON), # LT
makeRule(nil, binary, PREC_COMPARISON), # GE
makeRule(nil, binary, PREC_COMPARISON), # LE
makeRule(nil, binary, PREC_FACTOR), # MOD
makeRule(nil, binary, PREC_FACTOR), # POW
makeRule(nil, binary, PREC_COMPARISON), # GT
makeRule(grouping, nil, PREC_NONE), # LP
makeRule(nil, nil, PREC_NONE), # RP
makeRule(nil, nil, PREC_NONE), # LS
makeRule(nil, nil, PREC_NONE), # LB
makeRule(nil, nil, PREC_NONE), # RB
makeRule(nil, nil, PREC_NONE), # COMMA
makeRule(nil, nil, PREC_NONE), # DOT
makeRule(nil, nil, PREC_NONE), # ID
makeRule(nil, bracket, PREC_CALL), # RS
makeRule(number, nil, PREC_NONE), # NUMBER
makeRule(strVal, nil, PREC_NONE), # STR
makeRule(nil, nil, PREC_NONE), # SEMICOLON
makeRule(nil, nil, PREC_NONE), # AND
makeRule(nil, nil, PREC_NONE), # CLASS
makeRule(nil, nil, PREC_NONE), # ELSE
makeRule(nil, nil, PREC_NONE), # FOR
makeRule(nil, nil, PREC_NONE), # FUN
makeRule(literal, nil, PREC_NONE), # FALSE
makeRule(nil, nil, PREC_NONE), # IF
makeRule(literal, nil, PREC_NONE), # NIL
makeRule(nil, nil, PREC_NONE), # RETURN
makeRule(nil, nil, PREC_NONE), # SUPER
makeRule(nil, nil, PREC_NONE), # THIS
makeRule(nil, nil, PREC_NONE), # OR
makeRule(literal, nil, PREC_NONE), # TRUE
makeRule(nil, nil, PREC_NONE), # VAR
makeRule(nil, nil, PREC_NONE), # WHILE
makeRule(nil, nil, PREC_NONE), # DEL
makeRule(nil, nil, PREC_NONE), # BREAK
makeRule(nil, nil, PREC_NONE), # EOF
]
proc getRule(kind: TokenType): ParseRule =
return rules[kind]
result = rules[kind]
proc compile*(self: Compiler, source: string, chunk: Chunk): bool =
@ -228,7 +245,6 @@ proc compile*(self: Compiler, source: string, chunk: Chunk): bool =
var tokens = scanner.lex()
self.parser = initParser(tokens)
self.compilingChunk = chunk
discard self.parser.advance()
self.expression()
self.parser.consume(EOF, "Expecting end of file")
self.endCompiler()

View File

@ -104,11 +104,11 @@ proc parseNumber(self: var Lexer) =
discard self.step()
while self.peek().isDigit():
discard self.step()
var value = Value(kind: ValueTypes.FLOAT, floatValue: parseFloat(self.source[self.start..<self.current]))
self.tokens.add(self.createToken(TokenType.FLOAT, value))
var value = Value(kind: ValueTypes.DOUBLE, floatValue: parseFloat(self.source[self.start..<self.current]))
self.tokens.add(self.createToken(TokenType.NUMBER, value))
else:
var value = Value(kind: ValueTypes.INT, intValue: parseInt(self.source[self.start..<self.current]))
self.tokens.add(self.createToken(TokenType.INT, value))
var value = Value(kind: ValueTypes.INTEGER, intValue: parseInt(self.source[self.start..<self.current]))
self.tokens.add(self.createToken(TokenType.NUMBER, value))
proc parseIdentifier(self: var Lexer) =

BIN
nim/main

Binary file not shown.

View File

@ -13,6 +13,7 @@ proc repl(debug: bool = false) =
stdout.write(">>> ")
source = readLine(stdin)
except IOError:
echo ""
break
if source == "":
continue

View File

@ -10,7 +10,9 @@ type
OP_ADD,
OP_SUBTRACT,
OP_DIVIDE,
OP_MULTIPLY
OP_MULTIPLY,
OP_POW,
OP_MOD
Chunk* = ref object
consts*: ValueArray
code*: seq[uint8]
@ -18,7 +20,7 @@ type
proc initChunk*(): Chunk =
result = Chunk(consts: initValueArray(), code: @[], lines: @[])
result = Chunk(consts: ValueArray(values: @[]), code: @[], lines: @[])
proc writeChunk*(self: Chunk, byt: uint8, line: int) =

View File

@ -5,8 +5,8 @@ type
PLUS, MINUS, SLASH, STAR,
NEG, NE, EQ, DEQ, LT, GE,
LE, MOD, POW, GT, LP, RP, LS
LB, RB, COMMA, DOT, ID, RS
INT, FLOAT, BOOL, STR,
LB, RB, COMMA, DOT,
ID, RS, NUMBER, STR,
SEMICOLON, AND, CLASS,
ELSE, FOR, FUN, FALSE,
IF, NIL, RETURN, SUPER,

View File

@ -1,9 +1,9 @@
# Value objects
import strformat
# Value objects and types representation
type
ValueTypes* = enum
FLOAT, INT, BOOL, NIL, OBJECT
INTEGER, DOUBLE, BOOL, NIL, OBJECT
ObjectTypes* = enum
STRING,
Obj* = ref object
@ -12,10 +12,10 @@ type
str*: string
Value* = ref object
case kind*: ValueTypes
of FLOAT:
floatValue*: float
of INT:
of INTEGER:
intValue*: int
of DOUBLE:
floatValue*: float
of BOOL:
boolValue*: bool
of NIL:
@ -42,10 +42,10 @@ proc stringifyObject(obj: Obj): string =
proc stringifyValue*(value: Value): string =
case value.kind:
of FLOAT:
result = $value.floatValue
of INT:
of INTEGER:
result = $value.intValue
of DOUBLE:
result = $value.floatValue
of BOOL:
result = $value.boolValue
of NIL:

View File

@ -1 +0,0 @@
1 + 2 * 3

View File

@ -46,6 +46,10 @@ proc disassembleInstruction*(chunk: Chunk, offset: int): int =
result = simpleInstruction("OP_DIVIDE", offset)
elif opcode == OP_SUBTRACT:
result = simpleInstruction("OP_SUBTRACT", offset)
elif opcode == OP_MOD:
result = simpleInstruction("OP_MOD", offset)
elif opcode == OP_POW:
result = simpleInstruction("OP_POW", offset)
else:
echo &"Unknown opcode {opcode} at index {offset}"
result = offset + 1

View File

@ -4,8 +4,12 @@ import util/debug
import compiler
import strutils
import strformat
import math
import lenientops
proc `**`(a, b: int): int = pow(a.float, b.float).int
proc `**`(a, b: float): float = pow(a, b)
type InterpretResult = enum
OK,
@ -42,20 +46,28 @@ proc run(self: VM, debug: bool): InterpretResult =
copyMem(idx.addr, unsafeAddr(arr), sizeof(arr))
self.chunk.consts.values[idx]
template BinOp(op) =
var left = self.pop()
var right = self.pop()
if left.kind == FLOAT and right.kind == INT:
var res = `op`(left.floatValue, right.intValue)
self.push(Value(kind: FLOAT, floatValue: res))
elif left.kind == INT and right.kind == FLOAT:
var res = `op`(left.intValue, right.floatValue)
self.push(Value(kind: FLOAT, floatValue: res))
elif left.kind == INT and right.kind == INT:
var res = cast[int](`op`(left.intValue, right.intValue))
self.push(Value(kind: INT, intValue: res))
var leftVal = self.pop()
var rightVal = self.pop()
if leftVal.kind == INTEGER and rightVal.kind == INTEGER:
var left: int = leftVal.intValue
var right: int = rightVal.intValue
var res = `op`(right, left)
if res is int:
self.push(Value(kind: INTEGER, intValue: int res))
else:
self.push(Value(kind: DOUBLE, floatValue: float res))
elif leftVal.kind == DOUBLE and rightVal.kind == INTEGER:
var left = leftVal.floatValue
var right = float rightVal.intValue
self.push(Value(kind: DOUBLE, floatValue: `op`(right, left)))
elif leftVal.kind == INTEGER and rightVal.kind == DOUBLE:
var left = float leftVal.intValue
var right = rightVal.floatValue
self.push(Value(kind: DOUBLE, floatValue: `op`(right, left)))
else:
var res = `op`(left.floatValue, right.floatValue)
self.push(Value(kind: FLOAT, floatValue: res))
var left = leftVal.floatValue
var right = leftVal.floatValue
self.push(Value(kind: DOUBLE, floatValue: `op`(right, left)))
var instruction: uint8
var opcode: OpCode
while true:
@ -79,10 +91,10 @@ proc run(self: VM, debug: bool): InterpretResult =
of OP_NEGATE:
var cur = self.pop()
case cur.kind:
of FLOAT:
of DOUBLE:
cur.floatValue = -cur.floatValue
self.push(cur)
of INT:
of INTEGER:
cur.intValue = -cur.intValue
self.push(cur)
else:
@ -96,6 +108,10 @@ proc run(self: VM, debug: bool): InterpretResult =
BinOp(`/`)
of OP_MULTIPLY:
BinOp(`*`)
of OP_MOD:
BinOp(floorMod)
of OP_POW:
BinOp(`**`)
of OP_RETURN:
echo stringifyValue(self.pop())
return OK