mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 12:51:10 +00:00
Fix constant evaluation methods to return EvalResult
This commit is contained in:
parent
e2bd64ebe5
commit
e1eebb252f
7 changed files with 217 additions and 100 deletions
|
@ -35,6 +35,7 @@ pub enum ErrorKind {
|
||||||
PurityError,
|
PurityError,
|
||||||
HasEffect,
|
HasEffect,
|
||||||
MoveError,
|
MoveError,
|
||||||
|
NotConstExpr,
|
||||||
/* compile warnings */
|
/* compile warnings */
|
||||||
AttributeWarning = 60,
|
AttributeWarning = 60,
|
||||||
CastWarning,
|
CastWarning,
|
||||||
|
|
|
@ -47,15 +47,15 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_const(&mut self, name: &'static str, obj: ValueObj) {
|
pub(crate) fn register_const(&mut self, name: &str, obj: ValueObj) {
|
||||||
if self.consts.get(name).is_some() {
|
if self.consts.get(name).is_some() {
|
||||||
panic!("already registered: {name}");
|
panic!("already registered: {name}");
|
||||||
} else {
|
} else {
|
||||||
// TODO: visibility (not always private)
|
// TODO: visibility (not always private)
|
||||||
// TODO: kind (not always Builtin)
|
// TODO: kind (not always Builtin)
|
||||||
let vi = VarInfo::new(obj.t(), Const, Private, Builtin);
|
let vi = VarInfo::new(obj.t(), Const, Private, Builtin);
|
||||||
self.consts.insert(VarName::from_static(name), obj);
|
self.consts.insert(VarName::from_str(Str::rc(name)), obj);
|
||||||
self.locals.insert(VarName::from_static(name), vi);
|
self.locals.insert(VarName::from_str(Str::rc(name)), vi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::option::Option; // conflicting to Type::Option
|
use std::option::Option; // conflicting to Type::Option
|
||||||
|
|
||||||
use erg_common::traits::Locational;
|
use erg_common::traits::{Locational, Stream};
|
||||||
use erg_common::vis::Visibility;
|
use erg_common::vis::Visibility;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use erg_common::{enum_unwrap, get_hash, log, set};
|
use erg_common::{enum_unwrap, get_hash, log, set};
|
||||||
|
@ -315,30 +315,72 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 再帰サブルーチン/型の推論を可能にするため、予め登録しておく
|
// To allow forward references and recursive definitions
|
||||||
pub(crate) fn preregister(&mut self, block: &[ast::Expr]) -> TyCheckResult<()> {
|
pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> {
|
||||||
for expr in block.iter() {
|
for expr in block.iter() {
|
||||||
if let ast::Expr::Def(def) = expr {
|
if let ast::Expr::Def(def) = expr {
|
||||||
let id = Some(def.body.id);
|
let id = Some(def.body.id);
|
||||||
let __name__ = def.sig.ident().map(|i| i.inspect());
|
let __name__ = def.sig.ident().map(|i| i.inspect());
|
||||||
let mut eval_body_t = || {
|
|
||||||
self.eval_const_block(&def.body.block, __name__)
|
|
||||||
.map(|c| enum_t(set![c]))
|
|
||||||
};
|
|
||||||
match &def.sig {
|
match &def.sig {
|
||||||
ast::Signature::Subr(sig) => {
|
ast::Signature::Subr(sig) => {
|
||||||
let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() {
|
let const_t = if sig.is_const() {
|
||||||
Some(self.instantiate_typespec(spec, PreRegister)?)
|
match self.eval_const_block(&def.body.block, __name__) {
|
||||||
|
Ok(obj) => {
|
||||||
|
self.register_const(__name__.unwrap(), obj.clone());
|
||||||
|
Some(enum_t(set![obj]))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
eval_body_t()
|
None
|
||||||
|
};
|
||||||
|
let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() {
|
||||||
|
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
|
||||||
|
if let Some(const_t) = const_t {
|
||||||
|
self.sub_unify(
|
||||||
|
&const_t,
|
||||||
|
&spec_t,
|
||||||
|
Some(def.body.loc()),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Some(spec_t)
|
||||||
|
} else {
|
||||||
|
const_t
|
||||||
};
|
};
|
||||||
self.declare_sub(sig, opt_ret_t, id)?;
|
self.declare_sub(sig, opt_ret_t, id)?;
|
||||||
}
|
}
|
||||||
ast::Signature::Var(sig) if sig.is_const() => {
|
ast::Signature::Var(sig) if sig.is_const() => {
|
||||||
let t = if let Some(spec) = sig.t_spec.as_ref() {
|
let const_t = if sig.is_const() {
|
||||||
Some(self.instantiate_typespec(spec, PreRegister)?)
|
match self.eval_const_block(&def.body.block, __name__) {
|
||||||
|
Ok(obj) => {
|
||||||
|
self.register_const(__name__.unwrap(), obj.clone());
|
||||||
|
Some(enum_t(set![obj]))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
eval_body_t()
|
None
|
||||||
|
};
|
||||||
|
let t = if let Some(spec) = sig.t_spec.as_ref() {
|
||||||
|
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
|
||||||
|
if let Some(const_t) = const_t {
|
||||||
|
self.sub_unify(
|
||||||
|
&const_t,
|
||||||
|
&spec_t,
|
||||||
|
Some(def.body.loc()),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Some(spec_t)
|
||||||
|
} else {
|
||||||
|
const_t
|
||||||
};
|
};
|
||||||
self.declare_var(sig, t, id)?;
|
self.declare_var(sig, t, id)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1019,6 +1019,24 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
caused_by,
|
caused_by,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn not_const_expr(errno: usize, loc: Location, caused_by: Str) -> Self {
|
||||||
|
Self::new(
|
||||||
|
ErrorCore::new(
|
||||||
|
errno,
|
||||||
|
NotConstExpr,
|
||||||
|
loc,
|
||||||
|
switch_lang!(
|
||||||
|
"japanese" => "定数式ではありません",
|
||||||
|
"simplified_chinese" => "不是常量表达式",
|
||||||
|
"traditional_chinese" => "不是常量表達式",
|
||||||
|
"english" => "not a constant expression",
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
caused_by,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -3,9 +3,9 @@ use std::mem;
|
||||||
use erg_common::dict::Dict;
|
use erg_common::dict::Dict;
|
||||||
use erg_common::rccell::RcCell;
|
use erg_common::rccell::RcCell;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::traits::Stream;
|
use erg_common::traits::{Locational, Stream};
|
||||||
use erg_common::vis::Field;
|
use erg_common::vis::Field;
|
||||||
use erg_common::{dict, fn_name, set};
|
use erg_common::{dict, fn_name, option_enum_unwrap, set};
|
||||||
use erg_common::{RcArray, Str};
|
use erg_common::{RcArray, Str};
|
||||||
use OpKind::*;
|
use OpKind::*;
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ use erg_parser::ast::*;
|
||||||
use erg_parser::token::{Token, TokenKind};
|
use erg_parser::token::{Token, TokenKind};
|
||||||
|
|
||||||
use erg_type::constructors::{
|
use erg_type::constructors::{
|
||||||
enum_t, mono_proj, poly_class, poly_trait, ref_, ref_mut, refinement, subr_t,
|
class, enum_t, mono_proj, poly_class, poly_trait, ref_, ref_mut, refinement, subr_t,
|
||||||
};
|
};
|
||||||
use erg_type::typaram::{OpKind, TyParam};
|
use erg_type::typaram::{OpKind, TyParam};
|
||||||
use erg_type::value::ValueObj;
|
use erg_type::value::ValueObj;
|
||||||
use erg_type::{Predicate, SubrKind, TyBound, Type, ValueArgs};
|
use erg_type::{HasType, Predicate, SubrKind, TyBound, Type, ValueArgs};
|
||||||
|
|
||||||
use crate::context::instantiate::TyVarContext;
|
use crate::context::instantiate::TyVarContext;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
|
@ -41,7 +41,7 @@ pub fn type_from_token_kind(kind: TokenKind) -> Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_op_kind_from_token(kind: TokenKind) -> Result<OpKind, ()> {
|
fn try_get_op_kind_from_token(kind: TokenKind) -> EvalResult<OpKind> {
|
||||||
match kind {
|
match kind {
|
||||||
TokenKind::Plus => Ok(OpKind::Add),
|
TokenKind::Plus => Ok(OpKind::Add),
|
||||||
TokenKind::Minus => Ok(OpKind::Sub),
|
TokenKind::Minus => Ok(OpKind::Sub),
|
||||||
|
@ -63,7 +63,7 @@ fn try_get_op_kind_from_token(kind: TokenKind) -> Result<OpKind, ()> {
|
||||||
TokenKind::Shl => Ok(OpKind::Shl),
|
TokenKind::Shl => Ok(OpKind::Shl),
|
||||||
TokenKind::Shr => Ok(OpKind::Shr),
|
TokenKind::Shr => Ok(OpKind::Shr),
|
||||||
TokenKind::Mutate => Ok(OpKind::Mutate),
|
TokenKind::Mutate => Ok(OpKind::Mutate),
|
||||||
_other => Err(()),
|
_other => todo!("{_other}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,44 +166,58 @@ impl SubstContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
fn eval_const_acc(&self, _acc: &Accessor) -> Option<ValueObj> {
|
fn eval_const_acc(&self, acc: &Accessor) -> EvalResult<ValueObj> {
|
||||||
match _acc {
|
match acc {
|
||||||
Accessor::Local(local) => {
|
Accessor::Local(local) => {
|
||||||
if let Some(val) = self.rec_get_const_obj(local.inspect()) {
|
if let Some(val) = self.rec_get_const_obj(local.inspect()) {
|
||||||
Some(val.clone())
|
Ok(val.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
if local.is_const() {
|
||||||
|
Err(EvalError::no_var_error(
|
||||||
|
line!() as usize,
|
||||||
|
local.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
local.inspect(),
|
||||||
|
self.get_similar_name(local.inspect()),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(EvalError::not_const_expr(
|
||||||
|
line!() as usize,
|
||||||
|
acc.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Accessor::Attr(attr) => {
|
Accessor::Attr(attr) => {
|
||||||
let _obj = self.eval_const_expr(&attr.obj, None)?;
|
let _obj = self.eval_const_expr(&attr.obj, None);
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_bin(&self, bin: &BinOp) -> Option<ValueObj> {
|
fn eval_const_bin(&self, bin: &BinOp) -> EvalResult<ValueObj> {
|
||||||
match (bin.args[0].as_ref(), bin.args[1].as_ref()) {
|
match (bin.args[0].as_ref(), bin.args[1].as_ref()) {
|
||||||
(Expr::Lit(l), Expr::Lit(r)) => {
|
(Expr::Lit(l), Expr::Lit(r)) => {
|
||||||
let op = try_get_op_kind_from_token(bin.op.kind).ok()?;
|
let op = try_get_op_kind_from_token(bin.op.kind)?;
|
||||||
self.eval_bin_lit(op, eval_lit(l), eval_lit(r)).ok()
|
self.eval_bin_lit(op, eval_lit(l), eval_lit(r))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_unary(&self, unary: &UnaryOp) -> Option<ValueObj> {
|
fn eval_const_unary(&self, unary: &UnaryOp) -> EvalResult<ValueObj> {
|
||||||
match unary.args[0].as_ref() {
|
match unary.args[0].as_ref() {
|
||||||
Expr::Lit(lit) => {
|
Expr::Lit(lit) => {
|
||||||
let op = try_get_op_kind_from_token(unary.op.kind).ok()?;
|
let op = try_get_op_kind_from_token(unary.op.kind)?;
|
||||||
self.eval_unary_lit(op, eval_lit(lit)).ok()
|
self.eval_unary_lit(op, eval_lit(lit))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_args(&self, args: &Args, __name__: Option<&Str>) -> Option<ValueArgs> {
|
fn eval_args(&self, args: &Args, __name__: Option<&Str>) -> EvalResult<ValueArgs> {
|
||||||
let mut evaluated_pos_args = vec![];
|
let mut evaluated_pos_args = vec![];
|
||||||
for arg in args.pos_args().iter() {
|
for arg in args.pos_args().iter() {
|
||||||
let val = self.eval_const_expr(&arg.expr, __name__)?;
|
let val = self.eval_const_expr(&arg.expr, __name__)?;
|
||||||
|
@ -214,96 +228,116 @@ impl Context {
|
||||||
let val = self.eval_const_expr(&arg.expr, __name__)?;
|
let val = self.eval_const_expr(&arg.expr, __name__)?;
|
||||||
evaluated_kw_args.insert(arg.keyword.inspect().clone(), val);
|
evaluated_kw_args.insert(arg.keyword.inspect().clone(), val);
|
||||||
}
|
}
|
||||||
Some(ValueArgs::new(evaluated_pos_args, evaluated_kw_args))
|
Ok(ValueArgs::new(evaluated_pos_args, evaluated_kw_args))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_call(&self, call: &Call, __name__: Option<&Str>) -> Option<ValueObj> {
|
fn eval_const_call(&self, call: &Call, __name__: Option<&Str>) -> EvalResult<ValueObj> {
|
||||||
if let Expr::Accessor(acc) = call.obj.as_ref() {
|
if let Expr::Accessor(acc) = call.obj.as_ref() {
|
||||||
match acc {
|
match acc {
|
||||||
Accessor::Local(name) if name.is_const() => {
|
Accessor::Local(name) => {
|
||||||
if let Some(ValueObj::Subr(subr)) = self.rec_get_const_obj(&name.inspect()) {
|
let obj =
|
||||||
let subr = subr.clone();
|
self.rec_get_const_obj(&name.inspect())
|
||||||
let args = self.eval_args(&call.args, __name__)?;
|
.ok_or(EvalError::no_var_error(
|
||||||
Some(subr.call(args, __name__.map(|n| n.clone())))
|
line!() as usize,
|
||||||
} else {
|
name.loc(),
|
||||||
None
|
self.caused_by(),
|
||||||
}
|
name.inspect(),
|
||||||
|
self.get_similar_name(name.inspect()),
|
||||||
|
))?;
|
||||||
|
let subr = option_enum_unwrap!(obj, ValueObj::Subr)
|
||||||
|
.ok_or(EvalError::type_mismatch_error(
|
||||||
|
line!() as usize,
|
||||||
|
name.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
name.inspect(),
|
||||||
|
&class("Subroutine"),
|
||||||
|
&obj.t(),
|
||||||
|
None,
|
||||||
|
))?
|
||||||
|
.clone();
|
||||||
|
let args = self.eval_args(&call.args, __name__)?;
|
||||||
|
Ok(subr.call(args, __name__.map(|n| n.clone())))
|
||||||
}
|
}
|
||||||
Accessor::Local(_) => None,
|
|
||||||
Accessor::Attr(_attr) => todo!(),
|
Accessor::Attr(_attr) => todo!(),
|
||||||
Accessor::TupleAttr(_attr) => todo!(),
|
Accessor::TupleAttr(_attr) => todo!(),
|
||||||
Accessor::Public(_name) => todo!(),
|
Accessor::Public(_name) => todo!(),
|
||||||
Accessor::Subscr(_subscr) => todo!(),
|
Accessor::Subscr(_subscr) => todo!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_const_def(&mut self, def: &Def) -> Option<ValueObj> {
|
|
||||||
if def.is_const() {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_array(&self, arr: &Array) -> Option<ValueObj> {
|
fn eval_const_def(&mut self, def: &Def) -> EvalResult<ValueObj> {
|
||||||
|
if def.is_const() {
|
||||||
|
let __name__ = def.sig.ident().map(|i| i.inspect()).unwrap();
|
||||||
|
let obj = self.eval_const_block(&def.body.block, Some(__name__))?;
|
||||||
|
erg_common::log!();
|
||||||
|
self.register_const(__name__, obj);
|
||||||
|
Ok(ValueObj::None)
|
||||||
|
} else {
|
||||||
|
Err(EvalError::not_const_expr(
|
||||||
|
line!() as usize,
|
||||||
|
def.body.block.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_const_array(&self, arr: &Array) -> EvalResult<ValueObj> {
|
||||||
let mut elems = vec![];
|
let mut elems = vec![];
|
||||||
match arr {
|
match arr {
|
||||||
Array::Normal(arr) => {
|
Array::Normal(arr) => {
|
||||||
for elem in arr.elems.pos_args().iter() {
|
for elem in arr.elems.pos_args().iter() {
|
||||||
if let Some(elem) = self.eval_const_expr(&elem.expr, None) {
|
let elem = self.eval_const_expr(&elem.expr, None)?;
|
||||||
elems.push(elem);
|
elems.push(elem);
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return None;
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ValueObj::Array(RcArray::from(elems)))
|
Ok(ValueObj::Array(RcArray::from(elems)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_record(&mut self, record: &Record) -> Option<ValueObj> {
|
fn eval_const_record(&self, record: &Record) -> EvalResult<ValueObj> {
|
||||||
match record {
|
match record {
|
||||||
Record::Normal(rec) => self.eval_const_normal_record(rec),
|
Record::Normal(rec) => self.eval_const_normal_record(rec),
|
||||||
Record::Shortened(_rec) => unreachable!(), // should be desugared
|
Record::Shortened(_rec) => unreachable!(), // should be desugared
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_normal_record(&mut self, record: &NormalRecord) -> Option<ValueObj> {
|
fn eval_const_normal_record(&self, record: &NormalRecord) -> EvalResult<ValueObj> {
|
||||||
let mut attrs = vec![];
|
let mut attrs = vec![];
|
||||||
|
let mut record_ctx = Context::default(); // TODO: include outer context
|
||||||
for attr in record.attrs.iter() {
|
for attr in record.attrs.iter() {
|
||||||
let name = attr.sig.ident().map(|i| i.inspect());
|
let name = attr.sig.ident().map(|i| i.inspect());
|
||||||
if let Some(elem) = self.eval_const_block(&attr.body.block, name) {
|
let elem = record_ctx.eval_const_block(&attr.body.block, name)?;
|
||||||
let ident = match &attr.sig {
|
let ident = match &attr.sig {
|
||||||
Signature::Var(var) => match &var.pat {
|
Signature::Var(var) => match &var.pat {
|
||||||
VarPattern::Ident(ident) => {
|
VarPattern::Ident(ident) => Field::new(ident.vis(), ident.inspect().clone()),
|
||||||
Field::new(ident.vis(), ident.inspect().clone())
|
|
||||||
}
|
|
||||||
_ => todo!(),
|
|
||||||
},
|
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
},
|
||||||
attrs.push((ident, elem));
|
_ => todo!(),
|
||||||
} else {
|
};
|
||||||
return None;
|
attrs.push((ident, elem));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(ValueObj::Record(attrs.into_iter().collect()))
|
Ok(ValueObj::Record(attrs.into_iter().collect()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eval_const_expr(&self, expr: &Expr, __name__: Option<&Str>) -> Option<ValueObj> {
|
pub(crate) fn eval_const_expr(
|
||||||
|
&self,
|
||||||
|
expr: &Expr,
|
||||||
|
__name__: Option<&Str>,
|
||||||
|
) -> EvalResult<ValueObj> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Lit(lit) => Some(eval_lit(lit)),
|
Expr::Lit(lit) => Ok(eval_lit(lit)),
|
||||||
Expr::Accessor(acc) => self.eval_const_acc(acc),
|
Expr::Accessor(acc) => self.eval_const_acc(acc),
|
||||||
Expr::BinOp(bin) => self.eval_const_bin(bin),
|
Expr::BinOp(bin) => self.eval_const_bin(bin),
|
||||||
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
|
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
|
||||||
Expr::Call(call) => self.eval_const_call(call, __name__),
|
Expr::Call(call) => self.eval_const_call(call, __name__),
|
||||||
Expr::Array(arr) => self.eval_const_array(arr),
|
Expr::Array(arr) => self.eval_const_array(arr),
|
||||||
Expr::Record(rec) => todo!("{rec}"), // self.eval_const_record(rec),
|
Expr::Record(rec) => self.eval_const_record(rec),
|
||||||
Expr::Lambda(lambda) => todo!("{lambda}"),
|
Expr::Lambda(lambda) => todo!("{lambda}"),
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
}
|
}
|
||||||
|
@ -315,9 +349,9 @@ impl Context {
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
__name__: Option<&Str>,
|
__name__: Option<&Str>,
|
||||||
) -> Option<ValueObj> {
|
) -> EvalResult<ValueObj> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Lit(lit) => Some(eval_lit(lit)),
|
Expr::Lit(lit) => Ok(eval_lit(lit)),
|
||||||
Expr::Accessor(acc) => self.eval_const_acc(acc),
|
Expr::Accessor(acc) => self.eval_const_acc(acc),
|
||||||
Expr::BinOp(bin) => self.eval_const_bin(bin),
|
Expr::BinOp(bin) => self.eval_const_bin(bin),
|
||||||
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
|
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
|
||||||
|
@ -334,7 +368,7 @@ impl Context {
|
||||||
&mut self,
|
&mut self,
|
||||||
block: &Block,
|
block: &Block,
|
||||||
__name__: Option<&Str>,
|
__name__: Option<&Str>,
|
||||||
) -> Option<ValueObj> {
|
) -> EvalResult<ValueObj> {
|
||||||
for chunk in block.iter().rev().skip(1).rev() {
|
for chunk in block.iter().rev().skip(1).rev() {
|
||||||
self.eval_const_chunk(chunk, __name__)?;
|
self.eval_const_chunk(chunk, __name__)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ impl ASTLowerer {
|
||||||
fn gen_array_with_length_type(&self, elem: &hir::Expr, len: &ast::Expr) -> Type {
|
fn gen_array_with_length_type(&self, elem: &hir::Expr, len: &ast::Expr) -> Type {
|
||||||
let maybe_len = self.ctx.eval_const_expr(len, None);
|
let maybe_len = self.ctx.eval_const_expr(len, None);
|
||||||
match maybe_len {
|
match maybe_len {
|
||||||
Some(v @ ValueObj::Nat(_)) => {
|
Ok(v @ ValueObj::Nat(_)) => {
|
||||||
if elem.ref_t().is_mut() {
|
if elem.ref_t().is_mut() {
|
||||||
poly_class(
|
poly_class(
|
||||||
"ArrayWithMutType!",
|
"ArrayWithMutType!",
|
||||||
|
@ -174,7 +174,7 @@ impl ASTLowerer {
|
||||||
array(elem.t(), TyParam::Value(v))
|
array(elem.t(), TyParam::Value(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(v @ ValueObj::Mut(_)) if v.class() == class("Nat!") => {
|
Ok(v @ ValueObj::Mut(_)) if v.class() == class("Nat!") => {
|
||||||
if elem.ref_t().is_mut() {
|
if elem.ref_t().is_mut() {
|
||||||
poly_class(
|
poly_class(
|
||||||
"ArrayWithMutTypeAndLength!",
|
"ArrayWithMutTypeAndLength!",
|
||||||
|
@ -184,9 +184,9 @@ impl ASTLowerer {
|
||||||
array_mut(elem.t(), TyParam::Value(v))
|
array_mut(elem.t(), TyParam::Value(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(other) => todo!("{other} is not a Nat object"),
|
Ok(other) => todo!("{other} is not a Nat object"),
|
||||||
// TODO: [T; !_]
|
// REVIEW: is it ok to ignore the error?
|
||||||
None => {
|
Err(_e) => {
|
||||||
if elem.ref_t().is_mut() {
|
if elem.ref_t().is_mut() {
|
||||||
poly_class(
|
poly_class(
|
||||||
"ArrayWithMutType!",
|
"ArrayWithMutType!",
|
||||||
|
@ -366,12 +366,10 @@ impl ASTLowerer {
|
||||||
self.pop_append_errs();
|
self.pop_append_errs();
|
||||||
e
|
e
|
||||||
})?;
|
})?;
|
||||||
self.ctx
|
self.ctx.preregister(&lambda.body).map_err(|e| {
|
||||||
.preregister(lambda.body.ref_payload())
|
self.pop_append_errs();
|
||||||
.map_err(|e| {
|
e
|
||||||
self.pop_append_errs();
|
})?;
|
||||||
e
|
|
||||||
})?;
|
|
||||||
let body = self.lower_block(lambda.body).map_err(|e| {
|
let body = self.lower_block(lambda.body).map_err(|e| {
|
||||||
self.pop_append_errs();
|
self.pop_append_errs();
|
||||||
e
|
e
|
||||||
|
@ -437,7 +435,7 @@ impl ASTLowerer {
|
||||||
body: ast::DefBody,
|
body: ast::DefBody,
|
||||||
) -> LowerResult<hir::Def> {
|
) -> LowerResult<hir::Def> {
|
||||||
log!(info "entered {}({sig})", fn_name!());
|
log!(info "entered {}({sig})", fn_name!());
|
||||||
self.ctx.preregister(body.block.ref_payload())?;
|
self.ctx.preregister(&body.block)?;
|
||||||
let block = self.lower_block(body.block)?;
|
let block = self.lower_block(body.block)?;
|
||||||
let found_body_t = block.ref_t();
|
let found_body_t = block.ref_t();
|
||||||
let opt_expect_body_t = self
|
let opt_expect_body_t = self
|
||||||
|
@ -503,7 +501,7 @@ impl ASTLowerer {
|
||||||
.t
|
.t
|
||||||
.clone();
|
.clone();
|
||||||
self.ctx.assign_params(&sig.params, None)?;
|
self.ctx.assign_params(&sig.params, None)?;
|
||||||
self.ctx.preregister(body.block.ref_payload())?;
|
self.ctx.preregister(&body.block)?;
|
||||||
let block = self.lower_block(body.block)?;
|
let block = self.lower_block(body.block)?;
|
||||||
let found_body_t = block.ref_t();
|
let found_body_t = block.ref_t();
|
||||||
let expect_body_t = t.return_t().unwrap();
|
let expect_body_t = t.return_t().unwrap();
|
||||||
|
@ -556,7 +554,7 @@ impl ASTLowerer {
|
||||||
log!(info "the AST lowering process has started.");
|
log!(info "the AST lowering process has started.");
|
||||||
log!(info "the type-checking process has started.");
|
log!(info "the type-checking process has started.");
|
||||||
let mut module = hir::Module::with_capacity(ast.module.len());
|
let mut module = hir::Module::with_capacity(ast.module.len());
|
||||||
self.ctx.preregister(ast.module.ref_payload())?;
|
self.ctx.preregister(ast.module.block())?;
|
||||||
for expr in ast.module.into_iter() {
|
for expr in ast.module.into_iter() {
|
||||||
match self.lower_expr(expr).and_then(|e| self.use_check(e, mode)) {
|
match self.lower_expr(expr).and_then(|e| self.use_check(e, mode)) {
|
||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
|
|
|
@ -2846,7 +2846,7 @@ impl Expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Module(Vec<Expr>);
|
pub struct Module(Block);
|
||||||
|
|
||||||
impl fmt::Display for Module {
|
impl fmt::Display for Module {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -2860,7 +2860,31 @@ impl Locational for Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_stream_for_wrapper!(Module, Expr);
|
impl Stream<Expr> for Module {
|
||||||
|
fn payload(self) -> Vec<Expr> {
|
||||||
|
self.0.payload()
|
||||||
|
}
|
||||||
|
fn ref_payload(&self) -> &Vec<Expr> {
|
||||||
|
self.0.ref_payload()
|
||||||
|
}
|
||||||
|
fn ref_mut_payload(&mut self) -> &mut Vec<Expr> {
|
||||||
|
self.0.ref_mut_payload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self(Block::empty())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Self(Block::with_capacity(capacity))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block(&self) -> &Block {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AST {
|
pub struct AST {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue