Fixed precedence of is added beta support for the as operator for casting

This commit is contained in:
nocturn9x 2021-01-12 12:10:15 +01:00
parent 15072d3c56
commit 56938897d6
8 changed files with 71 additions and 11 deletions

View File

@ -66,9 +66,10 @@ type
Assign,
Or,
And,
Is,
Eq,
Comp,
As,
Is,
Term,
Factor,
Unary,
@ -319,6 +320,8 @@ proc binary(self: Compiler, canAssign: bool) =
self.emitByte(OpCode.Band)
of TokenType.IS:
self.emitByte(OpCode.Is)
of TokenType.AS:
self.emitByte(OpCode.As)
else:
discard # Unreachable
@ -1149,7 +1152,9 @@ var rules: array[TokenType, ParseRule] = [
makeRule(nil, binary, Precedence.Term), # BAND
makeRule(nil, binary, Precedence.Term), # BOR
makeRule(unary, nil, Precedence.None), # TILDE
makeRule(nil, binary, Precedence.Is) # IS
makeRule(nil, binary, Precedence.Is), # IS
makeRule(nil, binary, Precedence.As) # AS
]

View File

@ -56,9 +56,8 @@ const RESERVED = to_table({
"this": TokenType.THIS, "super": TokenType.SUPER,
"del": TokenType.DEL, "break": TokenType.BREAK,
"continue": TokenType.CONTINUE, "inf": TokenType.INF,
"nan": TokenType.NAN,
"is": TokenType.IS,
"not": TokenType.NEG})
"nan": TokenType.NAN, "is": TokenType.IS,
"not": TokenType.NEG, "as": TokenType.AS})
type
Lexer* = ref object
source*: string

View File

@ -69,7 +69,8 @@ type
Bor,
Band,
Bnot,
Is
Is,
As
@ -81,7 +82,7 @@ const simpleInstructions* = {OpCode.Return, OpCode.Add, OpCode.Multiply,
OpCode.Xor, OpCode.Not, OpCode.Equal,
OpCode.Greater, OpCode.Less, OpCode.GetItem,
OpCode.Slice, OpCode.Pop, OpCode.Negate,
OpCode.Is}
OpCode.Is, OpCode.As}
const constantInstructions* = {OpCode.Constant, OpCode.DefineGlobal,
OpCode.GetGlobal, OpCode.SetGlobal,
OpCode.DeleteGlobal}

View File

@ -29,7 +29,7 @@ type
WHILE, DEL, BREAK, EOF,
COLON, CONTINUE, CARET,
SHL, SHR, NAN, INF, BAND,
BOR, TILDE, IS
BOR, TILDE, IS, AS
Token* = ref object
kind*: TokenType
lexeme*: string

View File

@ -19,6 +19,7 @@ import baseObject
import numbers
import ../memory
import strutils
import strformat
type
@ -62,8 +63,10 @@ proc isFalsey*(self: ptr String): bool =
proc stringify*(self: ptr String): string =
result = self.toStr()
if self.len == 0:
result = "''"
else:
result = self.toStr()
proc typeName*(self: ptr String): string =
return "string"

View File

@ -24,6 +24,8 @@ import japlNil
import numbers
import native
import parseutils
proc typeName*(self: ptr Obj): string =
## Returns the name of the object's type
@ -403,6 +405,46 @@ proc gt*(self: ptr Obj, other: ptr Obj): bool =
raise newException(NotImplementedError, "")
proc objAs*(self: ptr Obj, other: ObjectType): ptr Obj =
## Returns the result of self as other
## (casts self to other's type)
# TODO -> This is in beta!
case other:
of ObjectType.String:
result = stringify(self).asStr()
of ObjectType.Integer:
case self.kind:
of ObjectType.String:
var intVal: int
discard parseInt(cast[ptr String](self).toStr(), intVal)
result = intVal.asInt()
of ObjectType.Float:
var floatVal: float64
discard (parseFloat(cast[ptr Float](self).stringify(), floatVal))
result = int(floatVal).asInt()
of ObjectType.Integer:
result = self
else:
raise newException(NotImplementedError, "")
of ObjectType.Float:
case self.kind:
of ObjectType.String:
var floatVal: float64
discard parseFloat(cast[ptr String](self).toStr(), floatVal)
result = floatVal.asFloat()
of ObjectType.Integer:
var intVal: int
discard parseInt(cast[ptr Integer](self).stringify(), intVal)
result = float(intVal).asFloat()
of ObjectType.Float:
result = self
else:
raise newException(NotImplementedError, "")
else:
raise newException(NotImplementedError, "")
## Utilities to inspect JAPL objects

View File

@ -326,6 +326,7 @@ proc readLongConstant(self: CallFrame): ptr Obj =
copyMem(idx.addr, unsafeAddr(arr), sizeof(arr))
result = self.function.chunk.consts[idx]
proc showRuntime*(self: VM, frame: CallFrame, iteration: uint64) =
## Shows debug information about the current
## state of the virtual machine
@ -526,6 +527,14 @@ proc run(self: VM, repl: bool): InterpretResult =
var right = self.pop()
var left = self.pop()
self.push(self.getBoolean(left == right))
of OpCode.As:
var right = self.pop()
var left = self.pop()
try:
self.push(objAs(left, right.kind))
except NotImplementedError:
self.error(newTypeError(&"unsupported binary operator 'as' for objects of type '{left.typeName()}' and '{right.typeName()}'"))
return RuntimeError
of OpCode.GetItem:
# TODO: More generic method
if not self.slice():
@ -617,6 +626,7 @@ proc run(self: VM, repl: bool): InterpretResult =
of OpCode.Return:
var retResult = self.pop()
if repl and not self.lastPop.isNil() and self.frameCount == 1:
# TODO -> Make this more efficient (move into japl.nim?)
# Prints the last expression to stdout as long as we're
# in REPL mode, the expression isn't nil and we're at the
# top-level code

View File

@ -9,7 +9,7 @@ print(true and 2);//output:2
print(false or 5);//output:5
print(0 or 4);//output:4
print(0 and true);//output:0
print("" and true);//output:
print("" and true);//output:''
print("" or true);//output:true
print(1 or 2 or 3 or 4);//output:1
print(1 and 2 and 3 and 4);//output:4