aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-09-06 13:19:22 +0200
committerHimbeer <himbeer@disroot.org>2024-09-06 13:56:07 +0200
commit959599b7bf803a91595375f650245609bf7a338f (patch)
tree47aafa8d49e00e45c0cb25255c8486eeec763692
parent05c620c4d637b73f6b267ed57d5750587ccfd7a3 (diff)
Add basic type system with only integers
This commit adds static typing with signed and unsigned integers of 8, 16, 32 and 64 bits.
-rw-r--r--decl.go23
-rw-r--r--expression.go56
-rw-r--r--generate.go312
-rw-r--r--generate_error.go52
-rw-r--r--parse.go16
-rw-r--r--type.go102
6 files changed, 501 insertions, 60 deletions
diff --git a/decl.go b/decl.go
index 67d641f..53c6c74 100644
--- a/decl.go
+++ b/decl.go
@@ -4,9 +4,26 @@
package main
-var funcs = map[string]struct{}{}
-var localConsts = map[string]map[string]string{}
-var localMuts = map[string]map[string]struct{}{}
+var funcs = map[string]*funcInfo{}
+var localConsts = map[string]map[string]*localConst{}
+var localMuts = map[string]map[string]*localMut{}
+
+type funcInfo struct {
+ params []paramInfo
+ returnType cerType
+}
+
+type paramInfo struct {
+ typ cerType
+}
+
+type localConst struct {
+ typ cerType
+}
+
+type localMut struct {
+ typ cerType
+}
func isDeclared(name string, toplevel bool) (ok bool, mutable bool) {
if toplevel {
diff --git a/expression.go b/expression.go
index 76cb16b..d042ebf 100644
--- a/expression.go
+++ b/expression.go
@@ -5,7 +5,6 @@
package main
import (
- "fmt"
"io"
)
@@ -63,19 +62,6 @@ func (p *paramExpr) markExpr() {}
func (p *paramExpr) line() int { return p.ln }
-func (p *paramExpr) String() string {
- if p == nil {
- return ""
- }
-
- s := fmt.Sprintf("%s %%%s", p.typ, p.name)
- if p.next != nil {
- s += p.next.String()
- }
-
- return s
-}
-
type externFuncExpr struct {
name string
params *signatureExpr
@@ -247,6 +233,7 @@ func (r *remAssignStmt) line() int { return r.ln }
type exprExpr interface {
expression
markExprExpr()
+ cerType() cerType
generate(io.Writer) (string, error)
}
@@ -262,6 +249,8 @@ func (e *equalityExpr) markExprExpr() {}
func (e *equalityExpr) line() int { return e.ln }
+func (e *equalityExpr) cerType() cerType { return e.lhs.cerType() }
+
type equalityRhs struct {
op equalityOp
value *comparisonExpr
@@ -279,6 +268,8 @@ func (c *comparisonExpr) markExprExpr() {}
func (c *comparisonExpr) line() int { return c.ln }
+func (c *comparisonExpr) cerType() cerType { return c.lhs.cerType() }
+
type comparisonRhs struct {
op comparisonOp
value *termExpr
@@ -296,6 +287,8 @@ func (t *termExpr) markExprExpr() {}
func (t *termExpr) line() int { return t.ln }
+func (t *termExpr) cerType() cerType { return t.lhs.cerType() }
+
type termRhs struct {
op shiftOp
value *numeralExpr
@@ -313,6 +306,8 @@ func (n *numeralExpr) markExprExpr() {}
func (n *numeralExpr) line() int { return n.ln }
+func (n *numeralExpr) cerType() cerType { return n.lhs.cerType() }
+
type numeralRhs struct {
op addSubOp
value *factorExpr
@@ -330,6 +325,8 @@ func (f *factorExpr) markExprExpr() {}
func (f *factorExpr) line() int { return f.ln }
+func (f *factorExpr) cerType() cerType { return f.lhs.cerType() }
+
type factorRhs struct {
op mulDivOp
value *unaryExpr
@@ -347,6 +344,8 @@ func (u *unaryExpr) markExprExpr() {}
func (u *unaryExpr) line() int { return u.ln }
+func (u *unaryExpr) cerType() cerType { return u.value.cerType() }
+
type primaryExpr interface {
exprExpr
markPrimaryExpr()
@@ -372,6 +371,8 @@ func (s *stringExpr) markLiteralExpr() {}
func (s *stringExpr) line() int { return s.ln }
+func (s *stringExpr) cerType() cerType { return nil } // TODO: string type
+
type numberExpr struct {
typ string
s string
@@ -388,6 +389,8 @@ func (n *numberExpr) markLiteralExpr() {}
func (n *numberExpr) line() int { return n.ln }
+func (n *numberExpr) cerType() cerType { return resolveType(n.typ) }
+
type groupingExpr struct {
inner exprExpr
ln int
@@ -401,9 +404,12 @@ func (g *groupingExpr) markPrimaryExpr() {}
func (g *groupingExpr) line() int { return g.ln }
+func (g *groupingExpr) cerType() cerType { return g.inner.cerType() }
+
type callExpr struct {
funcName string
args *argument
+ numArgs int
ln int
}
@@ -415,6 +421,15 @@ func (c *callExpr) markPrimaryExpr() {}
func (c *callExpr) line() int { return c.ln }
+func (c *callExpr) cerType() cerType {
+ ok, _ := isDeclared(c.funcName, true)
+ if !ok {
+ return nil
+ }
+
+ return funcs[c.funcName].returnType
+}
+
type argument struct {
value exprExpr
next *argument
@@ -432,3 +447,16 @@ func (v *varExpr) markExprExpr() {}
func (v *varExpr) markPrimaryExpr() {}
func (v *varExpr) line() int { return v.ln }
+
+func (v *varExpr) cerType() cerType {
+ ok, mutable := isDeclared(v.name, false)
+ if !ok {
+ return nil
+ }
+
+ if mutable {
+ return localMuts[currentFunc][v.name].typ
+ }
+
+ return localConsts[currentFunc][v.name].typ
+}
diff --git a/generate.go b/generate.go
index a32040a..15319b3 100644
--- a/generate.go
+++ b/generate.go
@@ -94,17 +94,30 @@ func generateFunction(function *functionExpr, w io.Writer) error {
currentFunc = function.name
defer func() { currentFunc = "" }()
- funcs[currentFunc] = struct{}{}
+ returnType := resolveType(function.returnType)
+ if returnType == nil {
+ return errUndeclared{
+ name: function.returnType,
+ kind: undeclaredType,
+ line: function.line(),
+ }
+ }
- localConsts[currentFunc] = map[string]string{}
- localMuts[currentFunc] = map[string]struct{}{}
+ funcs[currentFunc] = &funcInfo{returnType: returnType}
+
+ localConsts[currentFunc] = map[string]*localConst{}
+ localMuts[currentFunc] = map[string]*localMut{}
if function.link != defaultLinkage {
fmt.Fprintf(w, "%s ", function.link)
}
- fmt.Fprintf(w, "function %s $%s", function.returnType, function.name)
- fmt.Fprintf(w, "(%s) {\n", function.params)
+ fmt.Fprintf(w, "function %s $%s", returnType.qbeABIType(), function.name)
+ fmt.Fprintf(w, "(")
+ if err := generateParam(function.params, function.line(), w); err != nil {
+ return err
+ }
+ fmt.Fprintf(w, ") {\n")
fmt.Fprintln(w, "@start")
if err := generateBlock(function.blk, w); err != nil {
return err
@@ -114,12 +127,70 @@ func generateFunction(function *functionExpr, w io.Writer) error {
return nil
}
+func generateParam(p *paramExpr, line int, w io.Writer) error {
+ if p == nil {
+ return nil
+ }
+
+ typ := resolveType(p.typ)
+ if typ == nil {
+ return errUndeclared{name: p.typ, kind: undeclaredType, line: line}
+ }
+
+ funcs[currentFunc].params = append(funcs[currentFunc].params, paramInfo{
+ typ: typ,
+ })
+
+ fmt.Fprintf(w, "%s %%%s", typ.qbeABIType(), p.name)
+ if p.next != nil {
+ fmt.Fprintf(w, ", ")
+ if err := generateParam(p.next, line, w); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
func generateExternFunc(e *externFuncExpr, w io.Writer) error {
if ok, _ := isDeclared(e.name, true); ok {
return errAlreadyDeclared{name: e.name, line: e.line()}
}
- funcs[e.name] = struct{}{}
+ currentFunc = e.name
+ defer func() { currentFunc = "" }()
+
+ returnType := resolveType(e.returnType)
+
+ funcs[e.name] = &funcInfo{returnType: returnType}
+
+ if err := generateSignature(e.params, e.line(), w); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func generateSignature(s *signatureExpr, line int, w io.Writer) error {
+ if s == nil {
+ return nil
+ }
+
+ typ := resolveType(s.typ)
+ if typ == nil {
+ return errUndeclared{name: s.typ, kind: undeclaredType, line: line}
+ }
+
+ funcs[currentFunc].params = append(funcs[currentFunc].params, paramInfo{
+ typ: typ,
+ })
+
+ if s.next != nil {
+ if err := generateSignature(s.next, line, w); err != nil {
+ return err
+ }
+ }
+
return nil
}
@@ -159,6 +230,16 @@ func generateStatement(stmt statementExpr, w io.Writer) error {
}
func generateReturnStmt(stmt *returnStmt, w io.Writer) error {
+ returnType := funcs[currentFunc].returnType
+ valueType := stmt.value.cerType()
+ if valueType != returnType {
+ return errTypeMismatch{
+ expected: returnType,
+ got: valueType,
+ line: stmt.line(),
+ }
+ }
+
value, err := stmt.value.generate(w)
if err != nil {
return err
@@ -179,9 +260,12 @@ func generateConstStmt(stmt *constStmt, toplevel bool, w io.Writer) error {
return err
}
- localConsts[currentFunc][stmt.name] = value
+ typ := stmt.initial.cerType()
+ localConsts[currentFunc][stmt.name] = &localConst{
+ typ: typ,
+ }
- fmt.Fprintf(w, "%%%s =w add %s, 0\n", stmt.name, value)
+ fmt.Fprintf(w, "%%%s =%s add %s, 0\n", stmt.name, typ.qbeABIType(), value)
return nil
}
@@ -195,7 +279,10 @@ func generateMutStmt(stmt *mutStmt, toplevel bool, w io.Writer) error {
return err
}
- localMuts[currentFunc][stmt.name] = struct{}{}
+ typ := stmt.initial.cerType()
+ localMuts[currentFunc][stmt.name] = &localMut{
+ typ: typ,
+ }
fmt.Fprintf(w, "%%%s =l alloc4 4\n", stmt.name)
fmt.Fprintf(w, "storew %s, %%%s\n", value, stmt.name)
@@ -211,6 +298,16 @@ func generateAssignStmt(stmt *assignStmt, w io.Writer) error {
return errImmutable{name: stmt.name, line: stmt.line()}
}
+ varType := localMuts[currentFunc][stmt.name].typ
+ valueType := stmt.value.cerType()
+ if varType != valueType {
+ return errTypeMismatch{
+ expected: varType,
+ got: valueType,
+ line: stmt.line(),
+ }
+ }
+
value, err := stmt.value.generate(w)
if err != nil {
return err
@@ -229,6 +326,16 @@ func generateAddAssignStmt(stmt *addAssignStmt, w io.Writer) error {
return errImmutable{name: stmt.name, line: stmt.line()}
}
+ varType := localMuts[currentFunc][stmt.name].typ
+ valueType := stmt.value.cerType()
+ if varType != valueType {
+ return errTypeMismatch{
+ expected: varType,
+ got: valueType,
+ line: stmt.line(),
+ }
+ }
+
value, err := stmt.value.generate(w)
if err != nil {
return err
@@ -236,9 +343,13 @@ func generateAddAssignStmt(stmt *addAssignStmt, w io.Writer) error {
in, out := allocReg(), allocReg()
- fmt.Fprintf(w, "%s =w loadl %%%s\n", in, stmt.name)
- fmt.Fprintf(w, "%s =w add %s, %s\n", out, in, value)
- fmt.Fprintf(w, "storew %s, %%%s\n", out, stmt.name)
+ typ := varType.qbeBaseType()
+ loadType := varType.qbeABIType()
+ storeType := varType.qbeExtType()
+
+ fmt.Fprintf(w, "%s =%s load%s %%%s\n", in, typ, loadType, stmt.name)
+ fmt.Fprintf(w, "%s =%s add %s, %s\n", out, typ, in, value)
+ fmt.Fprintf(w, "store%s %s, %%%s\n", storeType, out, stmt.name)
return nil
}
@@ -251,6 +362,16 @@ func generateSubAssignStmt(stmt *subAssignStmt, w io.Writer) error {
return errImmutable{name: stmt.name, line: stmt.line()}
}
+ varType := localMuts[currentFunc][stmt.name].typ
+ valueType := stmt.value.cerType()
+ if varType != valueType {
+ return errTypeMismatch{
+ expected: varType,
+ got: valueType,
+ line: stmt.line(),
+ }
+ }
+
value, err := stmt.value.generate(w)
if err != nil {
return err
@@ -258,9 +379,13 @@ func generateSubAssignStmt(stmt *subAssignStmt, w io.Writer) error {
in, out := allocReg(), allocReg()
- fmt.Fprintf(w, "%s =w loadl %%%s\n", in, stmt.name)
- fmt.Fprintf(w, "%s =w sub %s, %s\n", out, in, value)
- fmt.Fprintf(w, "storew %s, %%%s\n", out, stmt.name)
+ typ := varType.qbeBaseType()
+ loadType := varType.qbeABIType()
+ storeType := varType.qbeExtType()
+
+ fmt.Fprintf(w, "%s =%s load%s %%%s\n", in, typ, loadType, stmt.name)
+ fmt.Fprintf(w, "%s =%s sub %s, %s\n", out, typ, in, value)
+ fmt.Fprintf(w, "store%s %s, %%%s\n", storeType, out, stmt.name)
return nil
}
@@ -273,6 +398,16 @@ func generateMulAssignStmt(stmt *mulAssignStmt, w io.Writer) error {
return errImmutable{name: stmt.name, line: stmt.line()}
}
+ varType := localMuts[currentFunc][stmt.name].typ
+ valueType := stmt.value.cerType()
+ if varType != valueType {
+ return errTypeMismatch{
+ expected: varType,
+ got: valueType,
+ line: stmt.line(),
+ }
+ }
+
value, err := stmt.value.generate(w)
if err != nil {
return err
@@ -280,9 +415,13 @@ func generateMulAssignStmt(stmt *mulAssignStmt, w io.Writer) error {
in, out := allocReg(), allocReg()
- fmt.Fprintf(w, "%s =w loadl %%%s\n", in, stmt.name)
- fmt.Fprintf(w, "%s =w mul %s, %s\n", out, in, value)
- fmt.Fprintf(w, "storew %s, %%%s\n", out, stmt.name)
+ typ := varType.qbeBaseType()
+ loadType := varType.qbeABIType()
+ storeType := varType.qbeExtType()
+
+ fmt.Fprintf(w, "%s =%s load%s %%%s\n", in, typ, loadType, stmt.name)
+ fmt.Fprintf(w, "%s =%s mul %s, %s\n", out, typ, in, value)
+ fmt.Fprintf(w, "store%s %s, %%%s\n", storeType, out, stmt.name)
return nil
}
@@ -295,6 +434,16 @@ func generateDivAssignStmt(stmt *divAssignStmt, w io.Writer) error {
return errImmutable{name: stmt.name, line: stmt.line()}
}
+ varType := localMuts[currentFunc][stmt.name].typ
+ valueType := stmt.value.cerType()
+ if varType != valueType {
+ return errTypeMismatch{
+ expected: varType,
+ got: valueType,
+ line: stmt.line(),
+ }
+ }
+
value, err := stmt.value.generate(w)
if err != nil {
return err
@@ -302,9 +451,13 @@ func generateDivAssignStmt(stmt *divAssignStmt, w io.Writer) error {
in, out := allocReg(), allocReg()
- fmt.Fprintf(w, "%s =w loadl %%%s\n", in, stmt.name)
- fmt.Fprintf(w, "%s =w div %s, %s\n", out, in, value)
- fmt.Fprintf(w, "storew %s, %%%s\n", out, stmt.name)
+ typ := varType.qbeBaseType()
+ loadType := varType.qbeABIType()
+ storeType := varType.qbeExtType()
+
+ fmt.Fprintf(w, "%s =%s load%s %%%s\n", in, typ, loadType, stmt.name)
+ fmt.Fprintf(w, "%s =%s div %s, %s\n", out, typ, in, value)
+ fmt.Fprintf(w, "store%s %s, %%%s\n", storeType, out, stmt.name)
return nil
}
@@ -317,6 +470,16 @@ func generateRemAssignStmt(stmt *remAssignStmt, w io.Writer) error {
return errImmutable{name: stmt.name, line: stmt.line()}
}
+ varType := localMuts[currentFunc][stmt.name].typ
+ valueType := stmt.value.cerType()
+ if varType != valueType {
+ return errTypeMismatch{
+ expected: varType,
+ got: valueType,
+ line: stmt.line(),
+ }
+ }
+
value, err := stmt.value.generate(w)
if err != nil {
return err
@@ -324,9 +487,13 @@ func generateRemAssignStmt(stmt *remAssignStmt, w io.Writer) error {
in, out := allocReg(), allocReg()
- fmt.Fprintf(w, "%s =w loadl %%%s\n", in, stmt.name)
- fmt.Fprintf(w, "%s =w rem %s, %s\n", out, in, value)
- fmt.Fprintf(w, "storew %s, %%%s\n", out, stmt.name)
+ typ := varType.qbeBaseType()
+ loadType := varType.qbeABIType()
+
+ storeType := varType.qbeExtType()
+ fmt.Fprintf(w, "%s =%s load%s %%%s\n", in, typ, loadType, stmt.name)
+ fmt.Fprintf(w, "%s =%s rem %s, %s\n", out, typ, in, value)
+ fmt.Fprintf(w, "store%s %s, %%%s\n", storeType, out, stmt.name)
return nil
}
@@ -338,6 +505,16 @@ func (e *equalityExpr) generate(w io.Writer) (string, error) {
out := lhs
for _, rhs := range e.rhs {
+ lhsType := e.lhs.cerType()
+ rhsType := rhs.value.cerType()
+ if rhsType != lhsType {
+ return "", errTypeMismatch{
+ expected: lhsType,
+ got: rhsType,
+ line: e.line(),
+ }
+ }
+
out, err = rhs.generate(out, w)
if err != nil {
return "", err
@@ -378,6 +555,16 @@ func (c *comparisonExpr) generate(w io.Writer) (string, error) {
out := lhs
if c.rhs != nil {
+ lhsType := c.lhs.cerType()
+ rhsType := c.rhs.value.cerType()
+ if rhsType != lhsType {
+ return "", errTypeMismatch{
+ expected: lhsType,
+ got: rhsType,
+ line: c.line(),
+ }
+ }
+
out, err = c.rhs.generate(out, w)
if err != nil {
return "", err
@@ -422,6 +609,16 @@ func (t *termExpr) generate(w io.Writer) (string, error) {
out := lhs
for _, rhs := range t.rhs {
+ lhsType := t.lhs.cerType()
+ rhsType := rhs.value.cerType()
+ if rhsType != lhsType {
+ return "", errTypeMismatch{
+ expected: lhsType,
+ got: rhsType,
+ line: t.line(),
+ }
+ }
+
out, err = rhs.generate(out, w)
if err != nil {
return "", err
@@ -460,6 +657,16 @@ func (n *numeralExpr) generate(w io.Writer) (string, error) {
out := lhs
for _, rhs := range n.rhs {
+ lhsType := n.lhs.cerType()
+ rhsType := rhs.value.cerType()
+ if rhsType != lhsType {
+ return "", errTypeMismatch{
+ expected: lhsType,
+ got: rhsType,
+ line: n.line(),
+ }
+ }
+
out, err = rhs.generate(out, w)
if err != nil {
return "", err
@@ -498,6 +705,16 @@ func (f *factorExpr) generate(w io.Writer) (string, error) {
out := lhs
for _, rhs := range f.rhs {
+ lhsType := f.lhs.cerType()
+ rhsType := rhs.value.cerType()
+ if rhsType != lhsType {
+ return "", errTypeMismatch{
+ expected: lhsType,
+ got: rhsType,
+ line: f.line(),
+ }
+ }
+
out, err = rhs.generate(out, w)
if err != nil {
return "", err
@@ -570,6 +787,15 @@ func (s *stringExpr) generate(w io.Writer) (string, error) {
}
func (n *numberExpr) generate(w io.Writer) (string, error) {
+ typ := resolveType(n.typ)
+ if typ == nil {
+ return "", errUndeclared{
+ name: n.typ,
+ kind: undeclaredType,
+ line: n.line(),
+ }
+ }
+
base := 10
switch {
case strings.HasPrefix(n.s, "0x"):
@@ -597,27 +823,53 @@ func (c *callExpr) generate(w io.Writer) (string, error) {
_, ok := funcs[c.funcName]
if !ok {
return "", errUndeclared{
- name: c.funcName,
- isFunc: true,
- line: c.line(),
+ name: c.funcName,
+ kind: undeclaredFunction,
+ line: c.line(),
}
}
+ returnType := funcs[c.funcName].returnType
+
ret := allocReg()
- fmt.Fprintf(w, "%s =w call $%s(", ret, c.funcName)
+ if c.numArgs != len(funcs[c.funcName].params) {
+ return "", errArgNumMismatch{
+ expected: len(funcs[c.funcName].params),
+ got: c.numArgs,
+ line: c.line(),
+ }
+ }
+ args := make([]string, 0)
delim := ""
+ i := 0
for arg := c.args; arg != nil; arg = arg.next {
reg, err := arg.value.generate(w)
if err != nil {
return "", err
}
- fmt.Fprintf(w, "w %s%s", reg, delim)
+ typ := arg.value.cerType()
+ neededType := funcs[c.funcName].params[i].typ
+ if typ != neededType {
+ return "", errTypeMismatch{
+ expected: neededType,
+ got: typ,
+ line: c.line(),
+ }
+ }
+
+ s := fmt.Sprintf("%s %s%s", typ.qbeABIType(), reg, delim)
+ args = append(args, s)
delim = ","
+ i++
}
+ fmt.Fprintf(w, "%s =%s call $%s(", ret, returnType.qbeABIType(), c.funcName)
+ for _, arg := range args {
+ fmt.Fprintf(w, "%s", arg)
+ }
fmt.Fprintf(w, ")\n")
return ret, nil
@@ -635,5 +887,5 @@ func (v *varExpr) generate(w io.Writer) (string, error) {
return reg, nil
}
- return localConsts[currentFunc][v.name], nil
+ return "%" + v.name, nil
}
diff --git a/generate_error.go b/generate_error.go
index e89add2..88fe3f4 100644
--- a/generate_error.go
+++ b/generate_error.go
@@ -15,19 +15,35 @@ func (e errAlreadyDeclared) Error() string {
return fmt.Sprintf("%d: redeclaration of %q\n", e.line, e.name)
}
+type undeclaredKind int
+
+const (
+ undeclaredVariable undeclaredKind = iota
+ undeclaredFunction
+ undeclaredType
+)
+
+func (u undeclaredKind) String() string {
+ switch u {
+ case undeclaredVariable:
+ return "variable"
+ case undeclaredFunction:
+ return "function"
+ case undeclaredType:
+ return "type"
+ default:
+ return "identifier"
+ }
+}
+
type errUndeclared struct {
- name string
- isFunc bool
- line int
+ name string
+ kind undeclaredKind
+ line int
}
func (e errUndeclared) Error() string {
- kind := "variable"
- if e.isFunc {
- kind = "function"
- }
-
- return fmt.Sprintf("%d: undeclared %s %q\n", e.line, kind, e.name)
+ return fmt.Sprintf("%d: undeclared %s %q\n", e.line, e.kind, e.name)
}
type errImmutable struct {
@@ -38,3 +54,21 @@ type errImmutable struct {
func (e errImmutable) Error() string {
return fmt.Sprintf("%d: cannot assign to constant %q\n", e.line, e.name)
}
+
+type errTypeMismatch struct {
+ expected, got cerType
+ line int
+}
+
+func (e errTypeMismatch) Error() string {
+ return fmt.Sprintf("%d: expected type %s, got %s", e.line, e.expected, e.got)
+}
+
+type errArgNumMismatch struct {
+ expected, got int
+ line int
+}
+
+func (e errArgNumMismatch) Error() string {
+ return fmt.Sprintf("%d: function expects %d arguments, got %d", e.line, e.expected, e.got)
+}
diff --git a/parse.go b/parse.go
index 8ac4c5d..f8da385 100644
--- a/parse.go
+++ b/parse.go
@@ -1267,7 +1267,8 @@ func parseCall(toks *tokens) (*callExpr, error) {
return nil, nil
}
- args, err := parseArg(toks)
+ numArgs := 0
+ args, err := parseArg(toks, &numArgs)
if err != nil {
return nil, err
}
@@ -1276,10 +1277,15 @@ func parseCall(toks *tokens) (*callExpr, error) {
return nil, err
}
- return &callExpr{funcName: nameTok.value, args: args, ln: nameTok.line}, nil
+ return &callExpr{
+ funcName: nameTok.value,
+ args: args,
+ numArgs: numArgs,
+ ln: nameTok.line,
+ }, nil
}
-func parseArg(toks *tokens) (*argument, error) {
+func parseArg(toks *tokens, numTotal *int) (*argument, error) {
ok, err := toks.match(rparen)
if err != nil {
return nil, err
@@ -1300,14 +1306,16 @@ func parseArg(toks *tokens) (*argument, error) {
}
if !ok {
toks.unreadToken()
+ *numTotal++
return &argument{value: arg}, nil
}
- next, err := parseArg(toks)
+ next, err := parseArg(toks, numTotal)
if err != nil {
return nil, err
}
+ *numTotal++
return &argument{value: arg, next: next}, nil
}
diff --git a/type.go b/type.go
new file mode 100644
index 0000000..d677472
--- /dev/null
+++ b/type.go
@@ -0,0 +1,102 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package main
+
+import "fmt"
+
+type cerType interface {
+ fmt.Stringer
+ qbeBaseType() string
+ qbeExtType() string
+ qbeABIType() string
+}
+
+type cerInteger struct {
+ bits int
+ unsigned bool
+}
+
+func (c cerInteger) String() string {
+ unsigned := ""
+ if c.unsigned {
+ unsigned = "u"
+ }
+
+ return fmt.Sprintf("%sint%d", unsigned, c.bits)
+}
+
+func (c cerInteger) qbeBaseType() string {
+ switch {
+ case c.bits > 32:
+ return "l"
+ default:
+ return "w"
+ }
+}
+
+func (c cerInteger) qbeExtType() string {
+ switch {
+ case c.bits > 32:
+ return "l"
+ case c.bits > 16:
+ return "w"
+ case c.bits > 8:
+ return "h"
+ default:
+ return "b"
+ }
+}
+
+func (c cerInteger) qbeABIType() string {
+ signedness := "s"
+ if c.unsigned {
+ signedness = "u"
+ }
+
+ switch {
+ case c.bits > 32:
+ return "l"
+ case c.bits > 16:
+ return "w"
+ case c.bits > 8:
+ return signedness + "h"
+ default:
+ return signedness + "b"
+ }
+}
+
+func resolveType(name string) cerType {
+ switch name {
+ case "int8":
+ return cerInteger{bits: 8}
+ case "uint8":
+ return cerInteger{bits: 8, unsigned: true}
+ case "int16":
+ return cerInteger{bits: 16}
+ case "uint16":
+ return cerInteger{bits: 16, unsigned: true}
+ case "int32":
+ return cerInteger{bits: 32}
+ case "uint32":
+ return cerInteger{bits: 32, unsigned: true}
+ case "int64":
+ return cerInteger{bits: 64}
+ case "uint64":
+ return cerInteger{bits: 64, unsigned: true}
+ default:
+ return nil
+ }
+}
+
+var (
+ cerInt8 = cerInteger{bits: 8}
+ cerUint8 = cerInteger{bits: 8, unsigned: true}
+ cerInt16 = cerInteger{bits: 16}
+ cerUint16 = cerInteger{bits: 16, unsigned: true}
+ cerInt32 = cerInteger{bits: 32}
+ cerUint32 = cerInteger{bits: 32, unsigned: true}
+ cerInt64 = cerInteger{bits: 64}
+ cerUint64 = cerInteger{bits: 64, unsigned: true}
+)