Exemple #1
0
func buildIdent(b *builder, ident *lex8.Token) tast.Expr {
	s := b.scope.Query(ident.Lit)
	if s == nil {
		b.Errorf(ident.Pos, "undefined identifier %s", ident.Lit)
		return nil
	}

	b.refSym(s, ident.Pos)

	t := s.ObjType.(types.T)
	switch s.Type {
	case tast.SymVar, tast.SymField:
		ref := tast.NewAddressableRef(t)
		return &tast.Ident{ident, ref, s}
	case tast.SymConst, tast.SymStruct, tast.SymType, tast.SymImport:
		ref := tast.NewRef(t)
		return &tast.Ident{ident, ref, s}
	case tast.SymFunc:
		if t, ok := t.(*types.Func); ok {
			if t.MethodFunc == nil {
				return &tast.Ident{ident, tast.NewRef(t), s}
			}
			if b.this == nil {
				panic("this missing")
			}
			ref := &tast.Ref{T: t.MethodFunc, Recv: b.this}
			return &tast.Ident{ident, ref, s}
		}
		return &tast.Ident{ident, tast.NewRef(t), s}
	default:
		b.Errorf(ident.Pos, "todo: token type: %s", tast.SymStr(s.Type))
		return nil
	}
}
Exemple #2
0
func buildPkgSym(
	b *builder, m *ast.MemberExpr, pkg *types.Pkg,
) (*tast.Ref, *sym8.Symbol) {
	sym := findPackageSym(b, m.Sub, pkg)
	if sym == nil {
		return nil, nil
	}

	if pkg.Lang == "asm8" {
		switch sym.Type {
		case asm8.SymVar:
			return tast.NewRef(types.Uint), sym
		case asm8.SymFunc:
			return tast.NewRef(types.VoidFunc), sym
		}

		b.Errorf(m.Sub.Pos, "invalid symbol %s in %s: %s",
			m.Sub.Lit, pkg, asm8.SymStr(sym.Type),
		)
		return nil, nil
	}
	t := sym.ObjType.(types.T)
	switch sym.Type {
	case tast.SymConst, tast.SymStruct, tast.SymFunc:
		return tast.NewRef(t), sym
	case tast.SymVar:
		return tast.NewAddressableRef(t), sym
	}

	b.Errorf(m.Sub.Pos, "bug: invalid symbol %s in %s: %s",
		m.Sub.Lit, pkg, tast.SymStr(sym.Type),
	)
	return nil, nil
}
Exemple #3
0
func binaryOpInt(
	b *builder, opTok *lex8.Token, A, B tast.Expr, t types.T,
) tast.Expr {
	op := opTok.Lit
	switch op {
	case "+", "-", "*", "&", "|", "^", "%", "/":
		r := tast.NewRef(t)
		return &tast.OpExpr{A, opTok, B, r}
	case "==", "!=", ">", "<", ">=", "<=":
		r := tast.NewRef(types.Bool)
		return &tast.OpExpr{A, opTok, B, r}
	}

	b.Errorf(opTok.Pos, "%q on ints", op)
	return nil
}
Exemple #4
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,
	}
}
Exemple #5
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
}
Exemple #6
0
func buildConstMember(b *builder, m *ast.MemberExpr) tast.Expr {
	obj := b.buildConstExpr(m.Expr)
	if obj == nil {
		return nil
	}

	ref := obj.R()
	if !ref.IsSingle() {
		b.Errorf(m.Dot.Pos, "%s does not have any member", ref)
		return nil
	}

	if pkg, ok := ref.T.(*types.Pkg); ok {
		s := findPackageSym(b, m.Sub, pkg)
		if s == nil {
			return nil
		}
		if s.Type != tast.SymConst {
			b.Errorf(m.Sub.Pos, "%s.%s is not a const", pkg, m.Sub.Lit)
			return nil
		}
		return &tast.Const{tast.NewRef(s.ObjType.(types.T))}
	}

	b.Errorf(m.Dot.Pos, "expect const expression")
	return nil
}
Exemple #7
0
func binaryOpSlice(b *builder, opTok *lex8.Token, A, B tast.Expr) tast.Expr {
	op := opTok.Lit
	switch op {
	case "==", "!=":
		return &tast.OpExpr{A, opTok, B, tast.NewRef(types.Bool)}
	}
	b.Errorf(opTok.Pos, "%q on slices", op)
	return nil
}
Exemple #8
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
}
Exemple #9
0
func binaryOpBool(b *builder, opTok *lex8.Token, A, B tast.Expr) tast.Expr {
	op := opTok.Lit
	switch op {
	case "==", "!=", "&&", "||":
		r := tast.NewRef(types.Bool)
		return &tast.OpExpr{A, opTok, B, r}
	}

	b.Errorf(opTok.Pos, "%q on bools", op)
	return nil
}
Exemple #10
0
func buildMethod(b *builder, f *pkgFunc) *tast.Func {
	this := f.recv.pt
	b.thisType = this
	if f.f.Recv != nil { // go-like, explicit receiver
		b.this = tast.NewAddressableRef(this)
	} else { // inlined
		b.this = tast.NewRef(this)
		b.scope.PushTable(f.recv.t.Syms)
		defer b.scope.Pop()
	}

	return buildFunc(b, f)
}
Exemple #11
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
}
Exemple #12
0
func buildCallLen(b *builder, expr *ast.CallExpr, f tast.Expr) tast.Expr {
	args := buildExprList(b, expr.Args)
	if args == nil {
		return nil
	}

	ref := args.R()
	if !ref.IsSingle() {
		b.Errorf(expr.Lparen.Pos, "len() takes one argument")
		return nil
	}

	t := ref.T
	switch t.(type) {
	case *types.Slice:
		return &tast.CallExpr{f, args, tast.NewRef(types.Int)}
	case *types.Array:
		return &tast.CallExpr{f, args, tast.NewRef(types.Int)}
	}

	b.Errorf(expr.Lparen.Pos, "len() does not take %s", t)
	return nil
}
Exemple #13
0
func buildConstIdent(b *builder, ident *lex8.Token) tast.Expr {
	s := b.scope.Query(ident.Lit)
	if s == nil {
		b.Errorf(ident.Pos, "undefined identifier %s", ident.Lit)
		return nil
	}

	b.refSym(s, ident.Pos)

	t := s.ObjType.(types.T)
	switch s.Type {
	case tast.SymConst:
		ref := tast.NewRef(t)
		return &tast.Const{ref}
	case tast.SymStruct, tast.SymType, tast.SymImport:
		ref := tast.NewRef(t)
		return &tast.Ident{ident, ref, s}
	}

	b.Errorf(ident.Pos, "%s is a %s; expect a const",
		ident.Lit, tast.SymStr(s.Type),
	)
	return nil
}
Exemple #14
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}
}
Exemple #15
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
}
Exemple #16
0
func buildCallMake(b *builder, expr *ast.CallExpr, f tast.Expr) tast.Expr {
	args := buildExprList(b, expr.Args)
	if args == nil {
		return nil
	}

	n := args.R().Len()
	if n == 0 {
		b.Errorf(expr.Lparen.Pos, "make() takes at least one argument")
		return nil
	}

	argsList, ok := tast.MakeExprList(args)
	if !ok {
		b.Errorf(expr.Lparen.Pos, "make() only takes a literal list")
		return nil
	}

	arg0 := argsList.Exprs[0]
	t, ok := arg0.R().T.(*types.Type)
	if !ok {
		b.Errorf(expr.Lparen.Pos, "make() takes a type as the 1st argument")
		return nil
	}
	switch st := t.T.(type) {
	case *types.Slice:
		if n != 3 {
			b.Errorf(expr.Lparen.Pos, "make() slice takes 3 arguments")
			return nil
		}

		size := argsList.Exprs[1]
		pos := ast.ExprPos(expr.Args.Exprs[1])
		size = checkArrayIndex(b, size, pos)
		if size == nil {
			return nil
		}

		start := argsList.Exprs[2]
		startType := start.R().T
		startPos := ast.ExprPos(expr.Args.Exprs[2])
		if v, ok := types.NumConst(startType); ok {
			start = constCastUint(b, startPos, v, start)
			if start == nil {
				return nil
			}
		} else if !types.IsBasic(startType, types.Uint) {
			pt := types.PointerOf(startType)
			if pt == nil || !types.SameType(pt, st.T) {
				b.Errorf(startPos,
					"make() takes an uint or a typed pointer as the 3rd arg",
				)
				return nil
			}
		}

		callArgs := tast.NewExprList()
		callArgs.Append(arg0)
		callArgs.Append(size)
		callArgs.Append(start)

		r := tast.NewRef(st)
		return &tast.CallExpr{f, callArgs, r}
	}

	b.Errorf(expr.Lparen.Pos, "cannot make() type %s", t.T)
	return nil
}
Exemple #17
0
func buildMember(b *builder, m *ast.MemberExpr) tast.Expr {
	obj := b.buildExpr(m.Expr)
	if obj == nil {
		return nil
	}

	ref := obj.R()
	if !ref.IsSingle() {
		b.Errorf(m.Dot.Pos, "%s does not have any member", ref)
		return nil
	}

	t := ref.T
	if pkg, ok := t.(*types.Pkg); ok {
		r, sym := buildPkgSym(b, m, pkg)
		if r == nil {
			return nil
		}
		// TODO: this can be further optimized
		return &tast.MemberExpr{obj, m.Sub, r, sym}
	}

	pt := types.PointerOf(t)
	var tstruct *types.Struct
	var ok bool
	if pt != nil {
		if tstruct, ok = pt.(*types.Struct); !ok {
			b.Errorf(m.Dot.Pos, "*%s is not a pointer of struct", t)
			return nil
		}
	} else {
		if tstruct, ok = t.(*types.Struct); !ok {
			b.Errorf(m.Dot.Pos, "%s is not a struct", t)
			return nil
		}
	}

	symTable := tstruct.Syms
	name := m.Sub.Lit
	sym := symTable.Query(name)
	if sym == nil {
		b.Errorf(m.Sub.Pos, "struct %s has no member named %s",
			tstruct, name,
		)
		return nil
	} else if !sym8.IsPublic(name) && sym.Pkg() != b.path {
		b.Errorf(m.Sub.Pos, "symbol %s is not public", name)
		return nil
	}

	b.refSym(sym, m.Sub.Pos)

	if sym.Type == tast.SymField {
		t := sym.ObjType.(types.T)
		r := tast.NewAddressableRef(t)
		return &tast.MemberExpr{obj, m.Sub, r, sym}
	} else if sym.Type == tast.SymFunc {
		ft := sym.ObjType.(*types.Func)
		r := tast.NewRef(ft.MethodFunc)
		r.Recv = ref
		return &tast.MemberExpr{obj, m.Sub, r, sym}
	}

	b.Errorf(m.Sub.Pos, "invalid sym type: %s", tast.SymStr(sym.Type))
	return nil
}
Exemple #18
0
func buildBinaryOpExpr(b *builder, expr *ast.OpExpr) tast.Expr {
	opTok := expr.Op
	op := opTok.Lit
	opPos := opTok.Pos

	A := b.buildExpr(expr.A)
	if A == nil {
		return nil
	}
	aref := A.R()
	if !aref.IsSingle() {
		b.Errorf(opPos, "%q on %s", op, aref)
		return nil
	}
	atyp := aref.T

	B := b.buildExpr(expr.B)
	if B == nil {
		return nil
	}
	bref := B.R()
	if !bref.IsSingle() {
		b.Errorf(opPos, "%q on %s", op, bref)
		return nil
	}
	btyp := bref.T

	if types.IsConst(atyp) && types.IsConst(btyp) {
		return binaryOpConst(b, opTok, A, B)
	}

	if op == ">>" || op == "<<" {
		if v, ok := types.NumConst(btyp); ok {
			B = constCast(b, opPos, v, B, types.Uint)
			if B == nil {
				return nil
			}
			btyp = types.Uint
		}

		if v, ok := types.NumConst(atyp); ok {
			A = constCast(b, opPos, v, A, types.Int)
			if A == nil {
				return nil
			}
			atyp = types.Int
		}

		if !canShift(b, atyp, btyp, opPos, op) {
			return nil
		}

		r := tast.NewRef(atyp)
		return &tast.OpExpr{A, opTok, B, r}
	}

	if v, ok := types.NumConst(atyp); ok {
		A = constCast(b, opPos, v, A, btyp)
		if A == nil {
			return nil
		}
		atyp = btyp
	} else if c, ok := atyp.(*types.Const); ok {
		atyp = c.Type
	}

	if v, ok := types.NumConst(btyp); ok {
		B = constCast(b, opPos, v, B, atyp)
		if B == nil {
			return nil
		}
		btyp = atyp
	} else if c, ok := btyp.(*types.Const); ok {
		btyp = c.Type
	}

	if ok, t := types.SameBasic(atyp, btyp); ok {
		switch t {
		case types.Int, types.Int8, types.Uint, types.Uint8:
			return binaryOpInt(b, opTok, A, B, t)
		case types.Bool:
			return binaryOpBool(b, opTok, A, B)
		case types.Float32:
			b.Errorf(opPos, "floating point operations not implemented")
			return nil
		}
	}

	if types.IsNil(atyp) && types.IsNil(btyp) {
		return binaryOpNil(b, opTok, A, B)
	} else if types.BothPointer(atyp, btyp) {
		return binaryOpPtr(b, opTok, A, B)
	} else if types.BothFuncPointer(atyp, btyp) {
		return binaryOpPtr(b, opTok, A, B)
	} else if types.BothSlice(atyp, btyp) {
		return binaryOpSlice(b, opTok, A, B)
	}

	b.Errorf(opPos, "invalid operation of %s %s %s", atyp, op, btyp)
	if types.IsInteger(atyp) && types.IsInteger(btyp) {
		switch op {
		case "+", "-", "*", "&", "|", "^", "%", "/",
			"==", "!=", ">", "<", ">=", "<=":
			b.Errorf(
				opPos,
				"operation %s needs the same type on both sides",
				op,
			)
		}
	}
	return nil
}
Exemple #19
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
}
Exemple #20
0
func buildCallExpr(b *builder, expr *ast.CallExpr) tast.Expr {
	f := b.buildExpr(expr.Func)
	if f == nil {
		return nil
	}

	pos := ast.ExprPos(expr.Func)
	fref := f.R()
	if !fref.IsSingle() {
		b.Errorf(pos, "%s is not callable", fref)
		return nil
	}
	if t, ok := fref.T.(*types.Type); ok {
		return buildCast(b, expr, t.T)
	}

	builtin, ok := fref.T.(*types.BuiltInFunc)
	if ok {
		switch builtin.Name {
		case "len":
			return buildCallLen(b, expr, f)
		case "make":
			return buildCallMake(b, expr, f)
		}
		b.Errorf(pos, "builtin %s() not implemented", builtin.Name)
		return nil
	}

	funcType, ok := fref.T.(*types.Func)
	if !ok {
		b.Errorf(pos, "function call on non-callable: %s", fref)
		return nil
	}

	args := buildExprList(b, expr.Args)
	if args == nil {
		return nil
	}

	argsRef := args.R()
	nargs := argsRef.Len()
	if nargs != len(funcType.Args) {
		b.Errorf(ast.ExprPos(expr), "argument expects (%s), got (%s)",
			fmt8.Join(funcType.Args, ","), args,
		)
		return nil
	}

	// type check on each argument
	for i := 0; i < nargs; i++ {
		argType := argsRef.At(i).Type()
		expect := funcType.Args[i].T
		if !types.CanAssign(expect, argType) {
			pos := ast.ExprPos(expr.Args.Exprs[i])
			b.Errorf(pos, "argument %d expects %s, got %s",
				i+1, expect, argType,
			)
			return nil
		}
	}

	// insert casting when it is a literal expression list.
	callArgs, ok := tast.MakeExprList(args)
	if ok {
		castedArgs := tast.NewExprList()
		for i := 0; i < nargs; i++ {
			argExpr := callArgs.Exprs[i]
			argType := argExpr.Type()
			expect := funcType.Args[i].T

			// insert auto casts for consts
			if types.IsNil(argType) {
				castedArgs.Append(tast.NewCast(argExpr, expect))
			} else if _, ok := types.NumConst(argType); ok {
				castedArgs.Append(tast.NewCast(argExpr, expect))
			} else {
				castedArgs.Append(argExpr)
			}
		}
		args = castedArgs
	}

	retRef := tast.Void
	for _, t := range funcType.RetTypes {
		retRef = tast.AppendRef(retRef, tast.NewRef(t))
	}

	return &tast.CallExpr{f, args, retRef}
}