1 Star 1 Fork 1

U语言组织 / U语言

forked from 秋来冬风 / U语言 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
file.go 5.61 KB
一键复制 编辑 原始数据 按行查看 历史
秋来冬风 提交于 2023-10-06 16:14 . 秋来冬风:build2支持for
package check2
import (
"fmt"
"strconv"
"strings"
"gitee.com/u-language/u-language/pkg/ast"
"gitee.com/u-language/u-language/pkg/enum"
"gitee.com/u-language/u-language/pkg/errcode"
"gitee.com/u-language/u-language/pkg/internal/errutil"
"gitee.com/u-language/u-language/pkg/internal/utils"
"gitee.com/u-language/u-language/pkg/ir2"
)
func CheckFile(f *ir2.File, errctx *errcode.ErrCtx) {
llen := len(f.VarInit)
for i := 0; i < llen; i++ { //检查变量初始化
checkIr(&f.VarInit[i], f.VarInit, &i, errctx, f)
}
llen = len(f.Ir)
for i := 0; i < llen; i++ { //检查指令
checkIr(&f.Ir[i], f.Ir, &i, errctx, f)
}
}
// checkIr 检查一条ir指令
func checkIr(v *ir2.IrNode, ir []ir2.IrNode, i *int, errctx *errcode.ErrCtx, f *ir2.File) (typ string) {
var err errcode.ErrCode
var msg errcode.Msg
switch v.Op {
case ir2.VarOP, ir2.TmpVarOP, ir2.RbraceOP, ir2.EndCallOp, ir2.ForOp, ir2.SemicolonOp, ir2.CommaOp, ir2.ObjOP, ir2.LbraceOp, ir2.LineFeedOp, ir2.ForEndOp: //无需检查
case ir2.ADDOP, ir2.SUBOP, ir2.MULOP, ir2.DIVOP, ir2.LessOp, ir2.GreaterOp, ir2.EqualOp, ir2.NoEqualOp: //运算
err, msg, typ = checkOp(v, ir, i)
case ir2.MOVOP: //赋值
err = checkMov(v, ir, i)
case ir2.CallOP: //调用
checkCall(v, ir, i, errctx, f)
case ir2.FuncOP:
f.FuncInfo = (**v.Func()).(*ast.FuncNode).FuncInfo
case ir2.RetOp: //返回
checkRet(v, ir, i, errctx, f)
case ir2.PaPaOp: //传递参数
checkPaPa(v, ir, i, errctx, f)
case ir2.LocalVarOp: //TODO:支持检查局部变量
default:
panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("未知的ir:%+v", *v)))
}
if err != errcode.NoErr {
errctx.Panic(f.FileName, *i+1, msg, err)
}
return typ
}
// checkOp 检查一个运算
func checkOp(v *ir2.IrNode, ir []ir2.IrNode, i *int) (errcode.ErrCode, errcode.Msg, string) {
decl := &ir[*i-1]
if isTmpVar(v.ResultObj) { //如果结果保存到临时变量
if decl.Op != ir2.TmpVarOP {
panic(errutil.NewErr2(errutil.CompileErr, "没发现临时变量"))
}
decl.Arg2Obj = v.Arg1Typ //设置临时变量类型
}
if !utils.Typ_is_equal(v.Arg1Typ, v.Arg2Typ) { //如果不是相同类型
return errcode.TypeIsNotEqual, errcode.NewMsgOpexprTypeIsNotEqual(v.Arg1Typ, v.Arg2Typ), ""
}
return errcode.NoErr, nil, v.Arg1Typ
}
// checkMov 检查一个赋值
func checkMov(v *ir2.IrNode, ir []ir2.IrNode, i *int) errcode.ErrCode {
if v.Arg2Obj != enum.StrFalse { //如果包含源操作数
if v.Arg1Typ != v.ResultTyp {
return errcode.TypeIsNotEqual
}
}
//TODO:支持不包含源操作数的类型检查
return errcode.NoErr
}
// isTmpVar 判断是不是临时变量
func isTmpVar(name string) bool {
return strings.HasPrefix(name, enum.Tmp)
}
// checkCall 检查一个调用
func checkCall(v *ir2.IrNode, ir []ir2.IrNode, i *int, errctx *errcode.ErrCtx, f *ir2.File) {
ok := predefined_func(v, f.Sbt, errctx, i, ir, f)
if ok { //如果是预定义的函数或视为函数调用的类型转换
return
}
info := f.Sbt.Have(v.Arg1Obj)
if info.Kind != enum.SymbolFunc && info.Kind != enum.SymbolMethod { //如果调用非函数
errctx.Panic(f.FileName, v.LineNum, errcode.NewMsgSymbol((**v.FuncName()).FuncName()), errcode.CallNoFunc)
}
if v.Arg2Obj == enum.StrFalse { //如果没有传参
return
}
*i++
for ; *i < len(ir); *i++ { //检查所有传参
if ir[*i].Op != ir2.PaPaOp {
checkIr(&ir[*i], ir, i, errctx, f)
}
}
}
// checkRet 检查一个返回
func checkRet(v *ir2.IrNode, ir []ir2.IrNode, i *int, errctx *errcode.ErrCtx, f *ir2.File) {
if v.Arg1Obj == "" { //如果没有返回值
if len(f.FuncInfo.RetValue) == 0 { //如果没有声明返回值
return
}
if v.Arg2Obj != enum.StrFalse { //如果返回值在后面
end, err := strconv.Atoi(v.ResultObj)
if err != nil {
panic(errutil.NewErr2(errutil.CompileErr, err.Error()))
}
for *i < end-1 { //检查返回值
*i++
checkIr(&ir[*i], ir, i, errctx, f)
}
*i++
typ := checkIr(&ir[*i], ir, i, errctx, f) //获取返回值类型
if typ == "" {
panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("找不到返回值类型")))
}
declType := f.FuncInfo.RetValue[0].Type.Typ()
if !utils.Typ_is_equal(typ, declType) { //如果类型不相等
errctx.Panic(f.FileName, v.LineNum, errcode.NewMsgReturnTypeIsNotEqual(declType, typ), errcode.ReturnErr)
}
return
}
errctx.Panic(f.FileName, v.LineNum, nil, errcode.RetWithValueInFuncWithoutValue)
return
}
tmp := v.Arg1Typ
declType := f.FuncInfo.RetValue[0].Type.Typ()
if !utils.Typ_is_equal(tmp, declType) { //如果类型不相等
errctx.Panic(f.FileName, v.LineNum, errcode.NewMsgReturnTypeIsNotEqual(declType, tmp), errcode.ReturnErr)
}
}
// checkPaPa 检查一个传参
func checkPaPa(v *ir2.IrNode, ir []ir2.IrNode, i *int, errctx *errcode.ErrCtx, f *ir2.File) {
n, err := strconv.Atoi(v.Arg1Obj)
if err != nil {
panic(errutil.NewErr2(errutil.CompileErr, err.Error()))
}
decl := f.FuncInfo.Parame[n]
tmp := findTmpTyp(v.Arg2Obj, i, ir)
decl_typ := decl.Type.Typ()
if !utils.Typ_is_equal(tmp, decl_typ) { //如果传递参数类型与声明参数类型不相等
errcode.Panic(f.FileName, v.LineNum, errcode.NewMsgCallTypeIsNotEqual(decl_typ, tmp, n), errcode.TypeIsNotEqual)
}
}
// findTmpTyp 获取临时变量的类型
func findTmpTyp(s string, i *int, ir []ir2.IrNode) string {
tmp := ""
//获取临时变量的类型
for index := *i; index >= 0; index-- {
if ir[index].Op == ir2.TmpVarOP && ir[index].Arg1Obj == s { //如果是临时变量的声明,其中有类型
tmp = ir[index].Arg2Obj
break
}
}
if tmp == "" {
panic(errutil.NewErr2(errutil.CompileErr, fmt.Sprintf("未找到临时变量 %s 类型", s)))
}
return tmp
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/u-language/u-language.git
git@gitee.com:u-language/u-language.git
u-language
u-language
U语言
0e42c1326373

搜索帮助

344bd9b3 5694891 D2dac590 5694891