func define( b *builder, ids []*lex8.Token, expr tast.Expr, eq *lex8.Token, ) *tast.Define { // check count matching r := expr.R() nleft := len(ids) nright := r.Len() if nleft != nright { b.Errorf(eq.Pos, "defined %d identifers with %d expressions", nleft, nright, ) return nil } if exprList, ok := tast.MakeExprList(expr); ok { exprList = allocPrepare(b, ids, exprList) if exprList == nil { return nil } expr = exprList } var syms []*sym8.Symbol ts := expr.R().TypeList() for i, tok := range ids { s := declareVar(b, tok, ts[i], false) if s == nil { return nil } syms = append(syms, s) } return &tast.Define{syms, expr} }
func buildSlicing( b *builder, expr *ast.IndexExpr, array tast.Expr, ) tast.Expr { t := array.R().T et := elementType(t) if et == nil { b.Errorf(expr.Lbrack.Pos, "slicing on neither array nor slice") return nil } var indexStart, indexEnd tast.Expr if expr.Index != nil { indexStart = buildArrayIndex(b, expr.Index, expr.Lbrack.Pos) if indexStart == nil { return nil } } if expr.IndexEnd != nil { indexEnd = buildArrayIndex(b, expr.IndexEnd, expr.Colon.Pos) if indexEnd == nil { return nil } } ref := tast.NewRef(&types.Slice{et}) return &tast.IndexExpr{ Array: array, Index: indexStart, IndexEnd: indexEnd, HasColon: true, Ref: ref, } }
func unaryOpConst(b *builder, opTok *lex8.Token, B tast.Expr) tast.Expr { op := opTok.Lit bref := B.R() if !bref.IsSingle() { b.Errorf(opTok.Pos, "invalid operation: %q on %s", op, bref) return nil } v, ok := types.NumConst(bref.T) if !ok { // TODO: support type const b.Errorf(opTok.Pos, "typed const operation not implemented") return nil } switch op { case "+": return B // just shortcut this case "-": return &tast.Const{tast.NewRef(types.NewNumber(-v))} } b.Errorf(opTok.Pos, "invalid operation: %q on %s", op, B) return nil }
func unaryOpBool(b *builder, opTok *lex8.Token, B tast.Expr) tast.Expr { op := opTok.Lit if op == "!" { t := B.R().T return &tast.OpExpr{nil, opTok, B, tast.NewRef(t)} } b.Errorf(opTok.Pos, "invalid operation: %q on boolean", op) return nil }
func unaryOpInt(b *builder, opTok *lex8.Token, B tast.Expr) tast.Expr { op := opTok.Lit switch op { case "+": return B case "-", "^": t := B.R().T return &tast.OpExpr{nil, opTok, B, tast.NewRef(t)} } b.Errorf(opTok.Pos, "invalid operation: %q on %s", op, B) return nil }
func checkArrayIndex(b *builder, index tast.Expr, pos *lex8.Pos) tast.Expr { t := index.R().T if v, ok := types.NumConst(t); ok { if v < 0 { b.Errorf(pos, "array index is negative: %d", v) return nil } return constCastInt(b, pos, v, index) } if !types.IsInteger(t) { b.Errorf(pos, "index must be an integer") return nil } return index }
func refAddress(b *builder, opTok *lex8.Token, B tast.Expr) tast.Expr { op := opTok.Lit opPos := opTok.Pos bref := B.R() if types.IsType(bref.T) || !bref.IsSingle() { b.Errorf(opPos, "%q on %s", op, bref) return nil } else if !bref.Addressable { b.Errorf(opPos, "reading address of non-addressable") return nil } r := tast.NewRef(&types.Pointer{bref.T}) return &tast.OpExpr{nil, opTok, B, r} }
func assign(b *builder, dest, src tast.Expr, op *lex8.Token) tast.Stmt { destRef := dest.R() srcRef := src.R() ndest := destRef.Len() nsrc := srcRef.Len() if ndest != nsrc { b.Errorf(op.Pos, "cannot assign %s to %s", nsrc, ndest) return nil } for i := 0; i < ndest; i++ { r := destRef.At(i) if !r.Addressable { b.Errorf(op.Pos, "assigning to non-addressable") return nil } destType := r.Type() srcType := srcRef.At(i).Type() if !types.CanAssign(destType, srcType) { b.Errorf(op.Pos, "cannot assign %s to %s", srcType, destType) return nil } } // insert casting if needed if srcList, ok := tast.MakeExprList(src); ok { newList := tast.NewExprList() for i, e := range srcList.Exprs { t := e.Type() if types.IsNil(t) { e = tast.NewCast(e, destRef.At(i).Type()) } else if v, ok := types.NumConst(t); ok { e = constCast(b, nil, v, e, destRef.At(i).Type()) if e == nil { panic("bug") } } newList.Append(e) } src = newList } return &tast.AssignStmt{dest, op, src} }
func binaryOpPtr(b *builder, opTok *lex8.Token, A, B tast.Expr) tast.Expr { op := opTok.Lit atyp := A.R().T btyp := B.R().T switch op { case "==", "!=": if types.IsNil(atyp) { A = tast.NewCast(A, btyp) } else if types.IsNil(btyp) { B = tast.NewCast(B, atyp) } return &tast.OpExpr{A, opTok, B, tast.NewRef(types.Bool)} } b.Errorf(opTok.Pos, "%q on pointers", op) return nil }
func opAssign(b *builder, dest, src tast.Expr, op *lex8.Token) tast.Stmt { destRef := dest.R() srcRef := src.R() if !destRef.IsSingle() || !srcRef.IsSingle() { b.Errorf(op.Pos, "%s %s %s", destRef, op.Lit, srcRef) return nil } else if !destRef.Addressable { b.Errorf(op.Pos, "assign to non-addressable") return nil } opLit := parseAssignOp(op.Lit) destType := destRef.Type() srcType := srcRef.Type() if opLit == ">>" || opLit == "<<" { if v, ok := types.NumConst(srcType); ok { src = constCast(b, op.Pos, v, src, types.Uint) if src == nil { return nil } srcRef = src.R() srcType = types.Uint } if !canShift(b, destType, srcType, op.Pos, opLit) { return nil } return &tast.AssignStmt{dest, op, src} } if v, ok := types.NumConst(srcType); ok { src = constCast(b, op.Pos, v, src, destType) if src == nil { return nil } srcRef = src.R() srcType = destType } if ok, t := types.SameBasic(destType, srcType); ok { switch t { case types.Int, types.Int8, types.Uint, types.Uint8: return &tast.AssignStmt{dest, op, src} } } b.Errorf(op.Pos, "invalid %s %s %s", destType, opLit, srcType) return nil }
func buildArrayGet( b *builder, expr *ast.IndexExpr, array tast.Expr, ) tast.Expr { t := array.R().T et := elementType(t) if et == nil { b.Errorf(expr.Lbrack.Pos, "index on neither array nor slice") return nil } index := buildArrayIndex(b, expr.Index, expr.Lbrack.Pos) if index == nil { return nil } ref := tast.NewAddressableRef(et) return &tast.IndexExpr{ Array: array, Index: index, Ref: ref, } }
func binaryOpConst(b *builder, opTok *lex8.Token, A, B tast.Expr) tast.Expr { op := opTok.Lit aref := A.R() bref := B.R() if aref.List != nil || bref.List != nil { b.Errorf(opTok.Pos, "invalid %s %q %s", aref.T, op, bref.T) return nil } va, oka := types.NumConst(aref.T) vb, okb := types.NumConst(bref.T) if !(oka && okb) { b.Errorf(opTok.Pos, "non-numeric consts ops not implemented") return nil } r := func(v int64) tast.Expr { return &tast.Const{tast.NewRef(types.NewNumber(v))} } switch op { case "+": return r(va + vb) case "-": return r(va - vb) case "*": return r(va * vb) case "&": return r(va & vb) case "|": return r(va | vb) case "^": return r(va ^ vb) case "%": if vb == 0 { b.Errorf(opTok.Pos, "modular by zero") return nil } return r(va % vb) case "/": if vb == 0 { b.Errorf(opTok.Pos, "divide by zero") return nil } return r(va / vb) case "==", "!=", ">", "<", ">=", "<=": return &tast.OpExpr{A, opTok, B, tast.NewRef(types.Bool)} case "<<": if vb < 0 { b.Errorf(opTok.Pos, "shift with negative value", vb) return nil } return r(va << uint64(vb)) case ">>": if vb < 0 { b.Errorf(opTok.Pos, "shift with negative value", vb) return nil } return r(va >> uint64(vb)) } b.Errorf(opTok.Pos, "%q on consts", op) return nil }