Skip to content

Commit

Permalink
cc: BROKEN variables WIP (binaryen stack issue)
Browse files Browse the repository at this point in the history
  • Loading branch information
math4tots committed Mar 18, 2021
1 parent b2c11a3 commit 89dcc84
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 9 deletions.
12 changes: 10 additions & 2 deletions src/main/cj/cjx/binaryen/Binaryen.cj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ native class Binaryen {
def optimize(self) = js!(Unit, self, ".optimize()")
def validate(self): Bool = js!(Bool, self, ".validate()")
def dispose(self) = js!(Unit, self, ".dispose()")
def autoDrop(self) = js!(Unit, self, ".autoDrop()")
def addGlobal(self, name: String, type: Type, mutable: Bool, value: Expression) = js!(
Unit, self, ".addGlobal(", name, ",", type, ",", mutable, ",", value, ")")
def setMemory(self, init: Int, max: Int) = js!(Unit, self, ".setMemory(", init, ",", max, ")")
def addFunction(
self,
name: String,
Expand Down Expand Up @@ -59,7 +61,13 @@ native class Binaryen {
def set(self, name: String, value: Expression): Expression = js!(
Expression, self, ".set(", name, ",", value, ")")
}
trait IntOps {
trait MemOps {
def load(self, offset: Int, align: Int, ptr: Expression): Expression = js!(
Expression, self, ".load(", offset, ",", align, ",", ptr, ")")
def store(self, offset: Int, align: Int, ptr: Expression, v: Expression): Expression = js!(
Expression, self, ".store(", offset, ",", align, ",", ptr, ",", v, ")")
}
trait IntOps : MemOps {
def const(self, value: Int): Expression = js!(
Expression, self, ".const(", value, ")")
def clz(self, value: Expression): Expression = js!(
Expand Down
45 changes: 44 additions & 1 deletion src/main/cj/cjx/cc/CCCodegen.cj
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,33 @@ class CCCodegen {
private static val unreachable: Binaryen.Type = Binaryen.unreachable
private static val auto: Binaryen.Type = Binaryen.auto

private static val localSlotSP = 0
private static val localSlotTmp = 1

private val m: Binaryen.Module = Binaryen.Module()

def emit(self, stmts: List[CCIR.Node]): Uint8Array {

m.addFunction("main", Binaryen.createType([]), i32, [], stmts(stmts))
m.setMemory(1, 1)

# initialize the stack pointer
m.addGlobal("SP", i32, true, m.i32.const(8))

m.addFunction("main", Binaryen.createType([]), i32, [i32, i32], stmts(stmts))
m.addFunctionExport("main", "main")

m.validate()
m.optimize()
IO.println(m.emitText())
m.emitBinary()
}

def stmts(self, stmts: List[CCIR.Node]): Binaryen.Expression {
val bexprs: List[Binaryen.Expression] = []

# initialize local variable '0' with "SP"
bexprs.add(m.local.set(localSlotSP, m.global.get("SP", i32)))

if stmts {
for i = 0; i + 1 < stmts.size(); i++ {
bexprs.add(m.drop(stmt(stmts[i])))
Expand All @@ -42,6 +57,25 @@ class CCCodegen {
}
}

def addr(self, expr: CCIR.Node): Binaryen.Expression {
when expr.kind {
case assign {
# TODO: Need to figure out how to use the stack somehow...
# binaryen doesn't seem to have a way to access this...
m.block(null, [
m.local.set(localSlotTmp, addr(expr.lhs)),
m.i32.store(0, 0, m.local.get(localSlotTmp, i32), expr(expr.rhs)),
m.local.get(localSlotTmp, i32),
], i32)
}
case var_ {
val var_ = expr.var_
m.i32.add(m.local.get(localSlotSP, i32), m.i32.const(var_.id * 8))
}
else = throw CCError("Not an lvalue", [expr.mark])
}
}

def expr(self, expr: CCIR.Node): Binaryen.Expression {
when expr.kind {
case int = m.i32.const(expr.intValue)
Expand All @@ -55,6 +89,15 @@ class CCCodegen {
case ne = m.i32.ne(expr(expr.lhs), expr(expr.rhs))
case lt = m.i32.lt_s(expr(expr.lhs), expr(expr.rhs))
case le = m.i32.le_s(expr(expr.lhs), expr(expr.rhs))
case assign {
val addr = addr(expr.lhs)
m.block(null, [
m.local.set(localSlotTmp, addr),
m.i32.store(0, 0, m.local.get(localSlotTmp, i32), expr(expr.rhs)),
m.i32.load(0, 0, m.local.get(localSlotTmp, i32)),
], auto)
}
case var_ = m.i32.load(0, 0, addr(expr))
else = throw CCError("TODO expr " + expr.kind, [expr.mark])
}
}
Expand Down
17 changes: 16 additions & 1 deletion src/main/cj/cjx/cc/CCIR.cj
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cjx.cc

import cj.Error
import cjx.parser.Mark

class CCIR {
Expand All @@ -13,6 +14,12 @@ class CCIR {
var base: Type = ?
}

## variable
class Obj {
val name: String
val id: Int
}

class Node {
union Kind: Repr, Hash {
case add
Expand All @@ -26,16 +33,20 @@ class CCIR {
case ne
case lt
case le
case assign
case exprStmt # expression statement
case var_
case int
def repr(self): String = tag_name!(self)
def __eq(self, other: Self): Bool = self is other
def hash(self): Int = tag!(self)
}

@implicit(Int, int)
@implicit(String, string)
union Value {
case int(Int)
case string(String)
}

val mark: Mark
Expand All @@ -49,8 +60,12 @@ class CCIR {
def __set_arg(self, node: Node) { lhs = node }
def __get_arg(self): Node = lhs

# var
var var_: Obj = ?

# literal value
var value: Value = ?
def __get_intValue(self): Int = when value { case int(i) = i }
def __get_intValue(self): Int = get!(value, int, 0)
def __get_stringValue(self): String = get!(value, string, 0)
}
}
2 changes: 2 additions & 0 deletions src/main/cj/cjx/cc/CCLexer.cj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class CCLexer {
b.add("0x[0-9A-Fa-f]+", m -> tok(m, CCToken.tINT, s -> s.parseInt().get())) # hex literals
b.add("\\d+", m -> tok(m, CCToken.tINT, s -> s.parseInt().get()))

b.add("[a-zA-Z_][a-zA-Z_0-9]*", m -> tok(m, CCToken.tIDENT, s -> s))

# single character symbol tokens
b.add(
"\\(|\\)|\\{|\\}|\\[|\\]|\\+|\\*|/|-|%|~|\\.|^|&|\\||!|@|=|;|,|:|<|>|\\?",
Expand Down
22 changes: 17 additions & 5 deletions src/main/cj/cjx/cc/CCParser.cj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cjx.cc

import cjx.parser.Mark
import cjx.cc.CCIR.Node
import cjx.cc.CCIR.Obj
import cjx.cc.CCError
import cjx.cc.CCLexer
import cjx.cc.CCToken
Expand Down Expand Up @@ -37,6 +38,8 @@ class CCParser: ParserMixin[CCToken] {
val tokens: List[CCToken]
var i = 0

val varMap: Map[String, Obj] = MapOf()

def mark(self): Mark = markAt(peek())
def markAt(self, token: CCToken): Mark = Mark(filepath, token.line, token.column)
def errorAt(self, message: String, token: CCToken): NoReturn = throw CCError(
Expand All @@ -59,17 +62,18 @@ class CCParser: ParserMixin[CCToken] {
while precedence < tokprec {
val mark = mark()
switch peek().type {
case '+' { next(); expr = binop(mark, Node.Kind.add, expr, exprpr(tokprec)) }
case '-' { next(); expr = binop(mark, Node.Kind.sub, expr, exprpr(tokprec)) }
case '*' { next(); expr = binop(mark, Node.Kind.mul, expr, exprpr(tokprec)) }
case '/' { next(); expr = binop(mark, Node.Kind.div, expr, exprpr(tokprec)) }
case '%' { next(); expr = binop(mark, Node.Kind.rem, expr, exprpr(tokprec)) }
case '+' { next(); expr = binop(mark, Node.Kind.add, expr, exprpr(tokprec)) }
case '-' { next(); expr = binop(mark, Node.Kind.sub, expr, exprpr(tokprec)) }
case '*' { next(); expr = binop(mark, Node.Kind.mul, expr, exprpr(tokprec)) }
case '/' { next(); expr = binop(mark, Node.Kind.div, expr, exprpr(tokprec)) }
case '%' { next(); expr = binop(mark, Node.Kind.rem, expr, exprpr(tokprec)) }
case CCToken.tEQ { next(); expr = binop(mark, Node.Kind.eq, expr, exprpr(tokprec)) }
case CCToken.tNE { next(); expr = binop(mark, Node.Kind.ne, expr, exprpr(tokprec)) }
case '<' { next(); expr = binop(mark, Node.Kind.lt, expr, exprpr(tokprec)) }
case CCToken.tLE { next(); expr = binop(mark, Node.Kind.le, expr, exprpr(tokprec)) }
case '>' { next(); expr = binop(mark, Node.Kind.lt, exprpr(tokprec), expr) }
case CCToken.tGE { next(); expr = binop(mark, Node.Kind.le, exprpr(tokprec), expr) }
case '=' { next(); expr = binop(mark, Node.Kind.assign, expr, exprpr(tokprec)) }
else = error("Unhandled operator " + peek().repr())
}
tokprec = precof(peek().type)
Expand All @@ -82,6 +86,7 @@ class CCParser: ParserMixin[CCToken] {
case '+'; case '-' = 100
case '<'; case '>'; case CCToken.tLE; case CCToken.tGE = 80
case CCToken.tEQ; case CCToken.tNE = 70
case '=' = 50
else = -1
}

Expand Down Expand Up @@ -116,6 +121,13 @@ class CCParser: ParserMixin[CCToken] {
case '+' { next(); unop(mark, Node.Kind.pos, atom()) }
case '-' { next(); unop(mark, Node.Kind.neg, atom()) }
case CCToken.tINT { literal(mark, Node.Kind.int, next().intValue) }
case CCToken.tIDENT {
val name = next().stringValue
val var_ = varMap.getOrInsert(name, () -> Obj(name, varMap.size()))
val node = Node(mark, Node.Kind.var_)
node.var_ = var_
node
}
else = errorKind("expression")
}
}
Expand Down
1 change: 1 addition & 0 deletions src/main/cj/cjx/cc/CCToken.cj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import cj.Error
class CCToken {
static val tEOF = 201
static val tINT = 202
static val tIDENT = 203

static val tEQ = 251
static val tNE = 252
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/js/prelude.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Error.stackTraceLimit = 100

/**
* Combines the hash in a way that is consistent with
* `java.util.List.hashCode` in the Java language.
Expand Down
7 changes: 7 additions & 0 deletions src/test/cj/cjx/cc/CCompilerTest.cj
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,11 @@ class CCompilerTest {

assertCode("1; 2; 3;", 3)
}

@test
def returnCodes2() {
assertCode("a=3; a;", 3)
assertCode("a=3; z=5; a+z;", 8)
assertCode("a=b=3; a+b; ", 13)
}
}

0 comments on commit 89dcc84

Please sign in to comment.