Beispiel #1
0
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}
}
Beispiel #2
0
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,
	}
}
Beispiel #3
0
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
}
Beispiel #4
0
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
}
Beispiel #5
0
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
}
Beispiel #6
0
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
}
Beispiel #7
0
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}
}
Beispiel #8
0
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}
}
Beispiel #9
0
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
}
Beispiel #10
0
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
}
Beispiel #11
0
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,
	}
}
Beispiel #12
0
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
}