mirror of https://github.com/japl-lang/japl.git
Added double-precision floating point numbers and integers. Implemented the 4 fundamental operations, modulo division and exponentiation
This commit is contained in:
parent
fe07ed4f49
commit
e4791ef027
104
nim/compiler.nim
104
nim/compiler.nim
|
@ -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()
|
||||
|
|
|
@ -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) =
|
||||
|
|
|
@ -13,6 +13,7 @@ proc repl(debug: bool = false) =
|
|||
stdout.write(">>> ")
|
||||
source = readLine(stdin)
|
||||
except IOError:
|
||||
echo ""
|
||||
break
|
||||
if source == "":
|
||||
continue
|
||||
|
|
|
@ -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) =
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
1 + 2 * 3
|
|
@ -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
|
||||
|
|
46
nim/vm.nim
46
nim/vm.nim
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue