예제 #1
0
파일: expr_list.go 프로젝트: 272489711/e8vm
func buildConstExprList(b *builder, list *ast.ExprList) tast.Expr {
	n := list.Len()
	if n == 0 {
		b.Errorf(ast.ExprPos(list), "const expression list of zero length")
		return nil
	}
	if n == 1 {
		return b.buildConst(list.Exprs[0])
	}

	ret := tast.NewExprList()
	for _, expr := range list.Exprs {
		ex := b.buildConst(expr)
		if ex == nil {
			return nil
		}
		ref := ex.R()
		if !ref.IsSingle() {
			b.Errorf(ast.ExprPos(expr), "cannot put %s in a list", ref)
			return nil
		}
		ret.Append(ex)
	}
	return ret
}
예제 #2
0
파일: expr_list.go 프로젝트: 272489711/e8vm
func buildExprList(b *builder, list *ast.ExprList) tast.Expr {
	ret := tast.NewExprList()
	if list == nil {
		return ret
	}
	n := list.Len()
	if n == 0 {
		return ret
	}
	if n == 1 {
		return b.buildExpr(list.Exprs[0])
	}

	for _, expr := range list.Exprs {
		ex := b.buildExpr(expr)
		if ex == nil {
			return nil
		}

		ref := ex.R()
		if !ref.IsSingle() {
			b.Errorf(ast.ExprPos(expr), "cannot put %s in a list", ref)
			return nil
		}

		ret.Append(ex)
	}
	return ret
}
예제 #3
0
파일: pkg_const.go 프로젝트: 272489711/e8vm
func buildPkgConstDecl(b *builder, d *ast.ConstDecl) []*pkgConst {
	if d.Type != nil {
		b.Errorf(ast.ExprPos(d.Type), "typed const not implemented")
		return nil
	}

	nident := len(d.Idents.Idents)
	nexpr := len(d.Exprs.Exprs)
	if nident != nexpr {
		b.Errorf(d.Eq.Pos, "%d consts with %d expressions",
			nident, nexpr,
		)
		return nil
	}

	var ret []*pkgConst
	zero := types.NewNumber(0) // place holding the const
	for i, ident := range d.Idents.Idents {
		s := declareConst(b, ident, zero)
		if s == nil {
			return nil
		}

		expr := d.Exprs.Exprs[i]
		c := &pkgConst{
			sym:  s,
			tok:  ident,
			expr: expr,
			deps: symUse(expr),
		}
		ret = append(ret, c)
	}

	return ret
}
예제 #4
0
파일: for.go 프로젝트: 272489711/e8vm
func buildForStmt(b *builder, stmt *ast.ForStmt) tast.Stmt {
	b.scope.Push()
	defer b.scope.Pop()

	ret := new(tast.ForStmt)
	if stmt.Init != nil {
		ret.Init = b.buildStmt(stmt.Init)
	}

	if stmt.Cond != nil {
		ret.Cond = b.buildExpr(stmt.Cond)
		if ret.Cond == nil {
			return nil
		}

		ref := ret.Cond.R()
		if !ref.IsBool() {
			pos := ast.ExprPos(stmt.Cond)
			b.Errorf(pos, "expect boolean expression, got %s", ref)
			return nil
		}
	}

	b.nloop++
	ret.Body = buildBlock(b, stmt.Body)
	b.nloop--

	if stmt.Iter != nil {
		ret.Iter = b.buildStmt(stmt.Iter)
	}
	return ret
}
예제 #5
0
파일: builder.go 프로젝트: NickDaison/e8vm
func (b *builder) buildConst(expr ast.Expr) *tast.Const {
	ret, ok := b.buildConstExpr(expr).(*tast.Const)
	if !ok {
		b.Errorf(ast.ExprPos(expr), "expect a const")
		return nil
	}
	return ret
}
예제 #6
0
파일: type.go 프로젝트: NickDaison/e8vm
func buildArrayType(b *builder, expr *ast.ArrayTypeExpr) types.T {
	t := buildType(b, expr.Type)
	if t == nil {
		return nil
	}

	if expr.Len == nil {
		// slice
		return &types.Slice{t}
	}

	// array
	n := b.buildConstExpr(expr.Len)
	if n == nil {
		return nil
	}

	ntype := n.R().T
	c, ok := ntype.(*types.Const)
	if !ok {
		// might be true, false, or other builtin consts
		b.Errorf(ast.ExprPos(expr), "array index is not a constant")
		return nil
	}

	if v, ok := types.NumConst(ntype); ok {
		if v < 0 {
			b.Errorf(ast.ExprPos(expr),
				"array index is negative: %d", c.Value,
			)
			return nil
		} else if !types.InRange(v, types.Int) {
			b.Errorf(ast.ExprPos(expr), "index out of range of int32")
			return nil
		}
		return &types.Array{T: t, N: int32(v)}
	}

	// TODO: support typed const
	b.Errorf(ast.ExprPos(expr), "typed const not implemented yet")
	return nil
}
예제 #7
0
파일: expr.go 프로젝트: NickDaison/e8vm
func buildExprStmt(b *builder, expr ast.Expr) tast.Stmt {
	if e, ok := expr.(*ast.CallExpr); ok {
		ret := buildExpr(b, e)
		if ret == nil {
			return nil
		}
		return &tast.ExprStmt{ret}
	}

	b.Errorf(ast.ExprPos(expr), "invalid expression statement")
	return nil
}
예제 #8
0
func buildConstDecl(b *builder, d *ast.ConstDecl) *tast.Define {
	if d.Type != nil {
		b.Errorf(ast.ExprPos(d.Type), "typed const not implemented yet")
		return nil
	}

	right := buildConstExprList(b, d.Exprs)
	if right == nil {
		return nil
	}

	nright := right.R().Len()
	idents := d.Idents.Idents
	nleft := len(idents)
	if nleft != nright {
		b.Errorf(d.Eq.Pos, "%d values for %d identifiers",
			nright, nleft,
		)
		return nil
	}

	var syms []*sym8.Symbol
	for i, ident := range idents {
		t := right.R().At(i).Type()
		if !types.IsConst(t) {
			b.Errorf(ast.ExprPos(d.Exprs.Exprs[i]), "not a const")
			return nil
		}

		sym := declareConst(b, ident, t)
		if sym == nil {
			return nil
		}
		syms = append(syms, sym)
	}

	return &tast.Define{syms, right}
}
예제 #9
0
파일: pkg_const.go 프로젝트: 272489711/e8vm
func buildPkgConst(b *builder, c *pkgConst) *sym8.Symbol {
	right := b.buildConstExpr(c.expr)
	if right == nil {
		return nil
	}
	res, ok := right.(*tast.Const)
	if !ok {
		b.Errorf(ast.ExprPos(c.expr), "expect a const")
		return nil
	}

	t := res.Ref.Type()
	c.sym.ObjType = t

	return c.sym
}
예제 #10
0
파일: define.go 프로젝트: Xslxy/e8vm
func buildDefineStmt(b *builder, stmt *ast.DefineStmt) tast.Stmt {
	right := b.buildExpr(stmt.Right)
	if right == nil {
		return nil
	}

	idents, err := buildIdentExprList(b, stmt.Left)
	if err != nil {
		b.Errorf(ast.ExprPos(err), "left side of := must be identifier")
		return nil
	}
	ret := define(b, idents, right, stmt.Define)
	if ret == nil {
		return nil
	}
	return ret
}
예제 #11
0
파일: expr.go 프로젝트: NickDaison/e8vm
func buildConstExpr(b *builder, expr ast.Expr) tast.Expr {
	if expr == nil {
		panic("bug")
	}

	switch expr := expr.(type) {
	case *ast.ParenExpr:
		return buildConstExpr(b, expr.Expr)
	case *ast.Operand:
		return buildConstOperand(b, expr)
	case *ast.MemberExpr:
		return buildConstMember(b, expr)
	case *ast.OpExpr:
		return buildConstOpExpr(b, expr)
	}

	b.Errorf(ast.ExprPos(expr), "expect a const expression")
	return nil
}
예제 #12
0
파일: expr.go 프로젝트: 272489711/e8vm
func buildExpr(b *builder, expr ast.Expr) tast.Expr {
	if expr == nil {
		panic("bug")
	}

	switch expr := expr.(type) {
	case *ast.Operand:
		return buildOperand(b, expr)
	case *ast.ParenExpr:
		return buildExpr(b, expr.Expr)
	case *ast.MemberExpr:
		return buildMember(b, expr)
	case *ast.OpExpr:
		return buildOpExpr(b, expr)
	case *ast.StarExpr:
		return buildStarExpr(b, expr)
	case *ast.IndexExpr:
		return buildIndexExpr(b, expr)
	case *ast.CallExpr:
		return buildCallExpr(b, expr)
	case *ast.ArrayTypeExpr:
		t := b.buildType(expr)
		if t == nil {
			return nil
		}
		return tast.NewType(t)
	case *ast.FuncTypeExpr:
		t := b.buildType(expr)
		if t == nil {
			return nil
		}
		return tast.NewType(t)
	case *ast.ExprList:
		return buildExprList(b, expr)
	case *ast.ArrayLiteral:
		return buildArrayLit(b, expr)
	}

	b.Errorf(ast.ExprPos(expr), "invalid or not implemented: %T", expr)
	return nil
}
예제 #13
0
파일: paras.go 프로젝트: 272489711/e8vm
func buildNamedParaList(b *builder, lst *ast.ParaList) []*types.Arg {
	ret := make([]*types.Arg, lst.Len())
	// named typeed list
	for i, para := range lst.Paras {
		if para.Ident == nil {
			b.Errorf(ast.ExprPos(para.Type),
				"expect identifer as argument name",
			)
			return nil
		}

		name := para.Ident.Lit
		if name == "_" {
			name = ""
		}
		ret[i] = &types.Arg{Name: name}

		if para.Type == nil {
			continue
		}

		t := b.buildType(para.Type)
		if t == nil {
			return nil
		}

		// go back and assign types
		for j := i; j >= 0 && ret[j].T == nil; j-- {
			ret[j].T = t
		}
	}

	// check that everything has a type
	if len(ret) > 0 && ret[len(ret)-1].T == nil {
		b.Errorf(lst.Rparen.Pos, "missing type in argument list")
		return nil
	}

	return ret
}
예제 #14
0
파일: var_decl.go 프로젝트: 272489711/e8vm
func buildVarDecl(b *builder, d *ast.VarDecl) *tast.Define {
	ids := d.Idents.Idents

	if d.Eq != nil {
		right := b.buildExpr(d.Exprs)
		if right == nil {
			return nil
		}

		if d.Type == nil {
			ret := define(b, ids, right, d.Eq)
			if ret == nil {
				return nil
			}
			return ret
		}

		tdest := b.buildType(d.Type)
		if tdest == nil {
			return nil
		}

		if !types.IsAllocable(tdest) {
			pos := ast.ExprPos(d.Type)
			b.Errorf(pos, "%s is not allocatable", tdest)
			return nil
		}

		// assignable check
		ts := right.R().TypeList()
		for _, t := range ts {
			if !types.CanAssign(tdest, t) {
				b.Errorf(d.Eq.Pos, "cannot assign %s to %s", t, tdest)
				return nil
			}
		}

		// cast literal expression lists
		// after the casting, all types should be matching to tdest
		if exprList, ok := tast.MakeExprList(right); ok {
			exprList = varDeclPrepare(b, ids, exprList, tdest)
			if exprList == nil {
				return nil
			}
			right = exprList
		}

		syms := declareVars(b, ids, tdest, false)
		if syms == nil {
			return nil
		}
		return &tast.Define{syms, right}
	}

	if d.Type == nil {
		panic("type missing")
	}

	t := b.buildType(d.Type)
	if t == nil {
		return nil
	}

	syms := declareVars(b, ids, t, false)
	if syms == nil {
		return nil
	}
	return &tast.Define{syms, nil}
}
예제 #15
0
파일: array_lit.go 프로젝트: 272489711/e8vm
func buildArrayLit(b *builder, lit *ast.ArrayLiteral) tast.Expr {
	hold := b.lhsSwap(false)
	defer b.lhsRestore(hold)

	if lit.Type.Len != nil {
		b.Errorf(
			ast.ExprPos(lit),
			"array literal with length not supported yet",
		)
		return nil
	}

	buf := new(bytes.Buffer)
	t := buildType(b, lit.Type.Type)
	if t == nil {
		return nil
	}

	if !types.IsInteger(t) {
		pos := ast.ExprPos(lit.Type.Type)
		b.Errorf(pos, "array literal must be integer type")
		return nil
	}
	bt := t.(types.Basic)

	if lit.Exprs != nil {
		for _, expr := range lit.Exprs.Exprs {
			n := b.buildConstExpr(expr)
			if n == nil {
				return nil
			}
			ntype := n.R().T
			if _, ok := ntype.(*types.Const); !ok {
				b.Errorf(ast.ExprPos(expr), "array literal not a constant")
				return nil
			}

			if v, ok := types.NumConst(ntype); ok {
				if !types.InRange(v, t) {
					b.Errorf(
						ast.ExprPos(expr),
						"constant out of range of %s",
						t,
					)
					return nil
				}

				switch bt {
				case types.Int, types.Uint:
					var bs [4]byte
					binary.LittleEndian.PutUint32(bs[:], uint32(v))
					buf.Write(bs[:])
				case types.Int8, types.Uint8:
					buf.Write([]byte{byte(v)})
				default:
					panic("not integer")
				}
			}
		}
	}

	ref := tast.NewConstRef(&types.Slice{bt}, buf.Bytes())
	return &tast.Const{ref}
}
예제 #16
0
파일: type.go 프로젝트: NickDaison/e8vm
func buildType(b *builder, expr ast.Expr) types.T {
	if expr == nil {
		panic("bug")
	}

	switch expr := expr.(type) {
	case *ast.Operand:
		ret := buildOperand(b, expr)
		if ret == nil {
			return nil
		}
		ref := ret.R()
		t, ok := ref.T.(*types.Type)
		if !ok {
			b.Errorf(ast.ExprPos(expr), "expect a type, got %s", ref.T)
			return nil
		}
		return t.T
	case *ast.StarExpr:
		t := buildType(b, expr.Expr)
		if t == nil {
			return nil
		}
		return &types.Pointer{t}
	case *ast.ArrayTypeExpr:
		return buildArrayType(b, expr)
	case *ast.ParenExpr:
		return buildType(b, expr.Expr)
	case *ast.FuncTypeExpr:
		return buildFuncType(b, nil, expr.FuncSig)
	case *ast.MemberExpr:
		op, ok := expr.Expr.(*ast.Operand)
		if !ok {
			b.Errorf(ast.ExprPos(expr.Expr), "expect a package")
			return nil
		}
		pkg := buildPkgRef(b, op.Token)
		if pkg == nil {
			return nil
		}
		name := expr.Sub.Lit
		s := pkg.Syms.Query(name)
		if s == nil {
			b.Errorf(expr.Sub.Pos, "symbol %s not found", name)
			return nil
		}
		if !sym8.IsPublic(name) && s.Pkg() != b.path {
			b.Errorf(expr.Sub.Pos, "symbol %s is not public", name)
			return nil
		}

		if s.Type != tast.SymStruct {
			b.Errorf(expr.Sub.Pos, "symbol %s is a %s, not a struct",
				name, tast.SymStr(s.Type),
			)
			return nil
		}

		return s.ObjType.(*types.Type).T
	}

	b.Errorf(ast.ExprPos(expr), "expect a type")
	return nil
}
예제 #17
0
파일: call.go 프로젝트: NickDaison/e8vm
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
}
예제 #18
0
파일: call.go 프로젝트: NickDaison/e8vm
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}
}