mirror of https://github.com/japl-lang/japl.git
Getting closer to compilability
This commit is contained in:
parent
0df6838941
commit
9d13f53e6d
|
@ -16,9 +16,9 @@
|
|||
import tables
|
||||
import strutils
|
||||
import meta/tokenobject
|
||||
import meta/japlvalue
|
||||
import types/stringtype
|
||||
import types/functiontype
|
||||
import types/japlvalue
|
||||
import types/string
|
||||
import types/function
|
||||
|
||||
|
||||
const FRAMES_MAX* = 400 # TODO: Inspect why the VM crashes if this exceeds 400
|
||||
|
|
17
compiler.nim
17
compiler.nim
|
@ -20,14 +20,13 @@ import algorithm
|
|||
import strformat
|
||||
import lexer
|
||||
import common
|
||||
import meta/chunk
|
||||
import meta/opcode
|
||||
import meta/tokenobject
|
||||
import meta/valueobject
|
||||
import meta/tokentype
|
||||
import meta/looptype
|
||||
import types/stringtype
|
||||
import types/functiontype
|
||||
import types/objecttype
|
||||
import types/japlvalue
|
||||
import types/string
|
||||
import types/function
|
||||
import tables
|
||||
when isMainModule:
|
||||
import util/debug
|
||||
|
@ -177,7 +176,7 @@ proc makeLongConstant(self: ref Compiler, val: Value): array[3, uint8] =
|
|||
proc emitConstant(self: ref Compiler, value: Value) =
|
||||
## Emits a Constant or ConstantLong instruction along
|
||||
## with its operand
|
||||
if self.currentChunk().consts.values.len > 255:
|
||||
if self.currentChunk().consts.len > 255:
|
||||
self.emitByte(OpCode.ConstantLong)
|
||||
self.emitBytes(self.makeLongConstant(value))
|
||||
else:
|
||||
|
@ -581,7 +580,7 @@ proc varDeclaration(self: ref Compiler) =
|
|||
var shortName: uint8
|
||||
var longName: array[3, uint8]
|
||||
var useShort: bool = true
|
||||
if self.currentChunk.consts.values.len < 255:
|
||||
if self.currentChunk.consts.len < 255:
|
||||
shortName = self.parseVariable("Expecting variable name")
|
||||
else:
|
||||
useShort = false
|
||||
|
@ -617,7 +616,7 @@ proc deleteVariable(self: ref Compiler, canAssign: bool) =
|
|||
else:
|
||||
code = OpCode.DeleteLocal
|
||||
self.localCount = self.localCount - 1
|
||||
if self.currentChunk.consts.values.len < 255:
|
||||
if self.currentChunk.consts.len < 255:
|
||||
var name = self.identifierConstant(self.parser.previous())
|
||||
self.emitBytes(code, name)
|
||||
else:
|
||||
|
@ -900,7 +899,7 @@ proc parseFunction(self: ref Compiler, funType: FunctionType) =
|
|||
self.parseBlock()
|
||||
var fun = self.endCompiler()
|
||||
self = self.enclosing
|
||||
if self.currentChunk.consts.values.len < 255:
|
||||
if self.currentChunk.consts.len < 255:
|
||||
self.emitBytes(OpCode.Constant, self.makeConstant(Value(kind: OBJECT, obj: fun)))
|
||||
else:
|
||||
self.emitByte(OpCode.ConstantLong)
|
||||
|
|
|
@ -29,7 +29,8 @@ import strformat
|
|||
import tables
|
||||
import meta/tokentype
|
||||
import meta/tokenobject
|
||||
import meta/valueobject
|
||||
import types/string
|
||||
import types/japlvalue
|
||||
|
||||
# Table of all tokens except reserved keywords
|
||||
const TOKENS = to_table({
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
|
||||
import segfaults
|
||||
import meta/japlvalue
|
||||
import types/japlvalue
|
||||
|
||||
|
||||
proc reallocate*(pointr: pointer, oldSize: int, newSize: int): pointer =
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
## The module dedicated to the Chunk type
|
||||
## A chunk is a piece of bytecode.
|
||||
|
||||
import japlvalue
|
||||
import ../types/japlvalue
|
||||
|
||||
type
|
||||
OpCode* {.pure.} = enum
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
import tokentype
|
||||
import japlvalue
|
||||
import ../types/japlvalue
|
||||
|
||||
# Token object
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
## Defines JAPL exceptions
|
||||
|
||||
import objecttype
|
||||
import stringtype
|
||||
import string
|
||||
import japlvalue
|
||||
import strformat
|
||||
import ../memory
|
||||
|
||||
|
@ -24,6 +24,8 @@ import ../memory
|
|||
proc stringify*(self: ptr JAPLException): string =
|
||||
return &"{self.errName.stringify}: {self.message.stringify}"
|
||||
|
||||
proc isFalsey*(self: ptr JAPLException): bool =
|
||||
return false
|
||||
|
||||
proc newTypeError*(message: string): ptr JAPLException =
|
||||
result = allocateObj(JAPLException, ObjectType.Exception)
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
# code objects that can be compiled inside the JAPL runtime, pretty much
|
||||
# like in Python
|
||||
|
||||
import stringtype
|
||||
import string
|
||||
import strformat
|
||||
import ../memory
|
||||
import ../meta/opcode
|
||||
import ../meta/japlvalue
|
||||
import japlvalue
|
||||
import tables
|
||||
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ type
|
|||
name*: ptr String
|
||||
arity*: int
|
||||
optionals*: int
|
||||
defaults*: Table[string, Obj]
|
||||
defaults*: Table[string, Value]
|
||||
chunk*: Chunk
|
||||
JAPLException* = object of Obj
|
||||
errName*: ptr String
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
# Copyright 2020 Mattia Giambirtone
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import japlvalue
|
||||
import string
|
||||
import function
|
||||
import exceptions
|
||||
import strutils
|
||||
|
||||
func stringify*(value: Value): string =
|
||||
case value.kind:
|
||||
|
@ -53,21 +72,24 @@ func bool*(value: Value): bool =
|
|||
of ValueType.Nan:
|
||||
result = true
|
||||
|
||||
func typeName*(obj: ptr Obj): string =
|
||||
case obj.kind:
|
||||
of ObjectType.String:
|
||||
result = cast[ptr String](obj).typeName()
|
||||
of ObjectType.Function:
|
||||
result = cast[ptr Function](obj).typeName()
|
||||
else:
|
||||
result = "" # TODO unimplemented
|
||||
|
||||
func typeName*(value: Value): string =
|
||||
case value.kind:
|
||||
of ValueType.Bool, ValueType.Nil, ValueType.Double,
|
||||
ValueType.Integer, ValueType.Nan, ValueType.Inf:
|
||||
result = ($value.kind).toLowerAscii()
|
||||
of ValueType.Minf:
|
||||
result = "inf"
|
||||
result = "inf"
|
||||
of ValueType.Object:
|
||||
case value.obj.kind:
|
||||
of ObjectType.String:
|
||||
result = cast[ptr String](value.obj).typeName()
|
||||
of ObjectType.Function:
|
||||
result = cast[ptr Function](value.obj).typeName()
|
||||
else:
|
||||
result = value.obj.typeName()
|
||||
result = typeName(value.obj)
|
||||
|
||||
proc eq*(a: Value, b: Value): bool =
|
||||
if a.kind != b.kind:
|
||||
|
@ -87,13 +109,14 @@ proc eq*(a: Value, b: Value): bool =
|
|||
of ObjectType.String:
|
||||
var a = cast[ptr String](a.obj)
|
||||
var b = cast[ptr String](b.obj)
|
||||
result = valuesEqual(a, b)
|
||||
result = eq(a, b)
|
||||
of ObjectType.Function:
|
||||
var a = cast[ptr Function](a.obj)
|
||||
var b = cast[ptr Function](b.obj)
|
||||
result = valuesEqual(a, b)
|
||||
result = eq(a, b)
|
||||
else:
|
||||
result = valuesEqual(a.obj, b.obj)
|
||||
result = false # TODO unimplemented
|
||||
|
||||
of ValueType.Inf:
|
||||
result = b.kind == ValueType.Inf
|
||||
of ValueType.Minf:
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# therefore immutable from the user's perspective. They are
|
||||
# natively ASCII encoded, but soon they will support for unicode.
|
||||
|
||||
import ../meta/japlvalue
|
||||
import japlvalue
|
||||
import strformat
|
||||
import ../memory
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
## This module takes chunks of bytecode, and prints their contents to the
|
||||
## screen.
|
||||
|
||||
import ../meta/chunk
|
||||
import ../meta/opcode
|
||||
import ../types/japlvalue
|
||||
import ../types/operations
|
||||
import ../common
|
||||
import strformat
|
||||
|
||||
|
@ -38,7 +40,7 @@ proc constantLongInstruction(name: string, chunk: Chunk, offset: int): int =
|
|||
var constant: int
|
||||
copyMem(constant.addr, unsafeAddr(constantArray), sizeof(constantArray))
|
||||
echo &"\tInstruction at IP: {name}, points to slot {constant}"
|
||||
let obj = chunk.consts.values[constant]
|
||||
let obj = chunk.consts[constant]
|
||||
echo &"\tOperand: {stringify(obj)}\n\tValue kind: {obj.kind}\n"
|
||||
return offset + 4
|
||||
|
||||
|
@ -46,7 +48,7 @@ proc constantLongInstruction(name: string, chunk: Chunk, offset: int): int =
|
|||
proc constantInstruction(name: string, chunk: Chunk, offset: int): int =
|
||||
var constant = chunk.code[offset + 1]
|
||||
echo &"\tInstruction at IP: {name}, points to index {constant}"
|
||||
let obj = chunk.consts.values[constant]
|
||||
let obj = chunk.consts[constant]
|
||||
echo &"\tOperand: {stringify(obj)}\n\tValue kind: {obj.kind}\n"
|
||||
return offset + 2
|
||||
|
||||
|
|
16
vm.nim
16
vm.nim
|
@ -24,12 +24,12 @@ import lenientops
|
|||
import common
|
||||
import compiler
|
||||
import tables
|
||||
import meta/chunk
|
||||
import meta/valueobject
|
||||
import meta/opcode
|
||||
import types/exceptions
|
||||
import types/objecttype
|
||||
import types/stringtype
|
||||
import types/functiontype
|
||||
import types/japlvalue
|
||||
import types/string
|
||||
import types/function
|
||||
import types/operations
|
||||
import memory
|
||||
when DEBUG_TRACE_VM:
|
||||
import util/debug
|
||||
|
@ -169,9 +169,9 @@ proc sliceRange(self: var VM): bool =
|
|||
of ObjectType.String:
|
||||
var str = popped.toStr()
|
||||
if sliceEnd.isNil():
|
||||
sliceEnd = Value(kind: INTEGER, intValue: len(str))
|
||||
sliceEnd = Value(kind: ValueType.Integer, intValue: len(str))
|
||||
if sliceStart.isNil():
|
||||
sliceStart = Value(kind: INTEGER, intValue: 0)
|
||||
sliceStart = Value(kind: ValueType.Integer, intValue: 0)
|
||||
elif not sliceStart.isInt() or not sliceEnd.isInt():
|
||||
self.error(newTypeError("string indeces must be integers"))
|
||||
return false
|
||||
|
@ -183,7 +183,7 @@ proc sliceRange(self: var VM): bool =
|
|||
self.push(Value(kind: OBJECT, obj: addObject(addr self, newString(""))))
|
||||
return true
|
||||
if sliceEnd.toInt() - 1 > len(str) - 1:
|
||||
sliceEnd = Value(kind: INTEGER, intValue: len(str))
|
||||
sliceEnd = Value(kind: ValueType.Integer, intValue: len(str))
|
||||
if sliceStart.toInt() > sliceEnd.toInt():
|
||||
self.push(Value(kind: OBJECT, obj: addObject(addr self, newString(""))))
|
||||
return true
|
||||
|
|
Loading…
Reference in New Issue