mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 12:14:43 +00:00
Fix bugs
This commit is contained in:
parent
afcf21787d
commit
ae15f95191
7 changed files with 159 additions and 57 deletions
|
@ -1522,7 +1522,7 @@ impl Context {
|
|||
}
|
||||
let path = name.split("::").next().unwrap_or(name);
|
||||
let path = path.split('.').next().unwrap_or(path);
|
||||
let path = self.cfg.input.resolve(Path::new(path)).ok()?;
|
||||
let path = self.resolve_path(Path::new(path));
|
||||
if let Some(ctx) = self
|
||||
.mod_cache
|
||||
.as_ref()
|
||||
|
@ -1545,7 +1545,7 @@ impl Context {
|
|||
// NOTE: This needs to be changed if we want to be able to define classes/traits outside of the top level
|
||||
let path = name.split("::").next().unwrap_or(name);
|
||||
let path = path.split('.').next().unwrap_or(path);
|
||||
let path = self.cfg.input.resolve(Path::new(path)).ok()?;
|
||||
let path = self.resolve_path(Path::new(path));
|
||||
if let Some(ctx) = self
|
||||
.mod_cache
|
||||
.as_ref()
|
||||
|
@ -1705,16 +1705,9 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる
|
||||
pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> {
|
||||
let t = self.get_var_info(name).map(|(_, vi)| vi.t.clone()).ok()?;
|
||||
match t {
|
||||
Type::Poly { name, mut params } if &name[..] == "Module" => {
|
||||
let path =
|
||||
option_enum_unwrap!(params.remove(0), TyParam::Value:(ValueObj::Str:(_)))?;
|
||||
let path = Path::new(&path[..]);
|
||||
// TODO: erg std
|
||||
let path = if let Ok(path) = self.cfg.input.resolve(path) {
|
||||
pub(crate) fn resolve_path(&self, path: &Path) -> PathBuf {
|
||||
if let Ok(path) = self.cfg.input.resolve(path) {
|
||||
path
|
||||
} else if let Ok(path) = erg_pystd_path()
|
||||
.join(format!("{}.d.er", path.display()))
|
||||
|
@ -1723,7 +1716,17 @@ impl Context {
|
|||
path
|
||||
} else {
|
||||
PathBuf::from(format!("<builtins>.{}", path.display()))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる
|
||||
pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> {
|
||||
let t = self.get_var_info(name).map(|(_, vi)| vi.t.clone()).ok()?;
|
||||
match t {
|
||||
Type::Poly { name, mut params } if &name[..] == "Module" => {
|
||||
let path =
|
||||
option_enum_unwrap!(params.remove(0), TyParam::Value:(ValueObj::Str:(_)))?;
|
||||
let path = self.resolve_path(Path::new(&path[..]));
|
||||
self.mod_cache
|
||||
.as_ref()
|
||||
.and_then(|cache| cache.ref_ctx(&path))
|
||||
|
|
|
@ -797,11 +797,11 @@ impl Context {
|
|||
TypeSpec::PreDeclTy(predecl) => {
|
||||
Ok(self.instantiate_predecl_t(predecl, opt_decl_t, tmp_tv_ctx)?)
|
||||
}
|
||||
TypeSpec::And(lhs, rhs) => Ok(self.union(
|
||||
TypeSpec::And(lhs, rhs) => Ok(self.intersection(
|
||||
&self.instantiate_typespec(lhs, opt_decl_t, tmp_tv_ctx, mode)?,
|
||||
&self.instantiate_typespec(rhs, opt_decl_t, tmp_tv_ctx, mode)?,
|
||||
)),
|
||||
TypeSpec::Or(lhs, rhs) => Ok(self.intersection(
|
||||
TypeSpec::Or(lhs, rhs) => Ok(self.union(
|
||||
&self.instantiate_typespec(lhs, opt_decl_t, tmp_tv_ctx, mode)?,
|
||||
&self.instantiate_typespec(rhs, opt_decl_t, tmp_tv_ctx, mode)?,
|
||||
)),
|
||||
|
|
|
@ -1 +1,14 @@
|
|||
.run!: (args: Str or [Str; _], shell := Bool) => NoneType
|
||||
.CompletedProcess: ClassType
|
||||
.CompletedProcess.args: Str or [Str; _]
|
||||
.CompletedProcess.returncode: Int
|
||||
.CompletedProcess.stdout: Bytes or NoneType
|
||||
.CompletedProcess.stderr: Bytes or NoneType
|
||||
|
||||
.run!: (
|
||||
args: Str or [Str; _],
|
||||
stdin: File! or NoneType := NoneType,
|
||||
stdout: File! or NoneType := NoneType,
|
||||
stderr: File! or NoneType := NoneType,
|
||||
capture_output := Bool,
|
||||
shell := Bool,
|
||||
) => .CompletedProcess
|
||||
|
|
|
@ -33,6 +33,10 @@ impl LexError {
|
|||
Self(core)
|
||||
}
|
||||
|
||||
pub fn set_hint<S: Into<AtomicStr>>(&mut self, hint: S) {
|
||||
self.0.hint = Some(hint.into());
|
||||
}
|
||||
|
||||
pub fn compiler_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self {
|
||||
Self::new(ErrorCore::new(
|
||||
errno,
|
||||
|
|
|
@ -349,7 +349,7 @@ impl Parser {
|
|||
if self.cur_is(TokenKind::AtSign) {
|
||||
self.lpop();
|
||||
let expr = self
|
||||
.try_reduce_expr(false, false, false)
|
||||
.try_reduce_expr(false, false, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(Some(Decorator::new(expr)))
|
||||
|
@ -436,7 +436,7 @@ impl Parser {
|
|||
Some(semi) if semi.is(Semi) => {
|
||||
self.lpop();
|
||||
let len = self
|
||||
.try_reduce_expr(false, false, false)
|
||||
.try_reduce_expr(false, false, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
return Ok(ArrayInner::WithLength(elems.remove_pos(0), len));
|
||||
|
@ -493,7 +493,7 @@ impl Parser {
|
|||
match self.peek() {
|
||||
Some(_) => {
|
||||
let expr = self
|
||||
.try_reduce_expr(false, false, false)
|
||||
.try_reduce_expr(false, false, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(PosArg::new(expr))
|
||||
|
@ -667,7 +667,6 @@ impl Parser {
|
|||
}
|
||||
if self.nth_is(1, Walrus) {
|
||||
let acc = self.try_reduce_acc_lhs().map_err(|_| self.stack_dec())?;
|
||||
// TODO: type specification
|
||||
debug_power_assert!(self.cur_is(Walrus));
|
||||
self.skip();
|
||||
let kw = if let Accessor::Ident(n) = acc {
|
||||
|
@ -680,21 +679,52 @@ impl Parser {
|
|||
return Err(());
|
||||
};
|
||||
let expr = self
|
||||
.try_reduce_expr(false, in_type_args, false)
|
||||
.try_reduce_expr(false, in_type_args, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(PosOrKwArg::Kw(KwArg::new(kw, None, expr)))
|
||||
} else {
|
||||
let expr = self
|
||||
.try_reduce_expr(false, in_type_args, false)
|
||||
.try_reduce_expr(false, in_type_args, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
if self.cur_is(Walrus) {
|
||||
self.skip();
|
||||
let (kw, t_spec) = match expr {
|
||||
Expr::Accessor(Accessor::Ident(n)) => (n.name.into_token(), None),
|
||||
Expr::TypeAsc(tasc) => {
|
||||
if let Expr::Accessor(Accessor::Ident(n)) = *tasc.expr {
|
||||
let t_spec = TypeSpecWithOp::new(tasc.op, tasc.t_spec);
|
||||
(n.name.into_token(), Some(t_spec))
|
||||
} else {
|
||||
self.next_expr();
|
||||
self.level -= 1;
|
||||
let err = ParseError::simple_syntax_error(0, tasc.loc());
|
||||
self.errs.push(err);
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.next_expr();
|
||||
self.level -= 1;
|
||||
let err = ParseError::simple_syntax_error(0, expr.loc());
|
||||
self.errs.push(err);
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
let expr = self
|
||||
.try_reduce_expr(false, in_type_args, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(PosOrKwArg::Kw(KwArg::new(kw, t_spec, expr)))
|
||||
} else {
|
||||
self.level -= 1;
|
||||
Ok(PosOrKwArg::Pos(PosArg::new(expr)))
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(_) => {
|
||||
let expr = self
|
||||
.try_reduce_expr(false, in_type_args, false)
|
||||
.try_reduce_expr(false, in_type_args, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(PosOrKwArg::Pos(PosArg::new(expr)))
|
||||
|
@ -731,7 +761,7 @@ impl Parser {
|
|||
None
|
||||
};*/
|
||||
let expr = self
|
||||
.try_reduce_expr(false, in_type_args, false)
|
||||
.try_reduce_expr(false, in_type_args, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(KwArg::new(keyword, None, expr))
|
||||
|
@ -834,7 +864,7 @@ impl Parser {
|
|||
Ok(Lambda::new(sig, op, body, self.counter))
|
||||
} else {
|
||||
let expr = self
|
||||
.try_reduce_expr(true, false, false)
|
||||
.try_reduce_expr(true, false, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
let block = Block::new(vec![expr]);
|
||||
self.level -= 1;
|
||||
|
@ -901,7 +931,7 @@ impl Parser {
|
|||
let op = self.lpop();
|
||||
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||
let t_spec = self
|
||||
.try_reduce_expr(false, false, false)
|
||||
.try_reduce_expr(false, false, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
let t_spec = Self::expr_to_type_spec(t_spec).map_err(|e| self.errs.push(e))?;
|
||||
let expr = Expr::TypeAsc(TypeAscription::new(lhs, op, t_spec));
|
||||
|
@ -1055,7 +1085,7 @@ impl Parser {
|
|||
};
|
||||
self.skip();
|
||||
let index = self
|
||||
.try_reduce_expr(false, false, in_brace)
|
||||
.try_reduce_expr(false, false, in_brace, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
let r_sqbr = self.lpop();
|
||||
if !r_sqbr.is(RSqBr) {
|
||||
|
@ -1071,7 +1101,7 @@ impl Parser {
|
|||
Some(t) if t.is(Comma) && winding => {
|
||||
let first_elem = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||
let tup = self
|
||||
.try_reduce_tuple(first_elem)
|
||||
.try_reduce_tuple(first_elem, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
stack.push(ExprOrOp::Expr(Expr::Tuple(tup)));
|
||||
}
|
||||
|
@ -1131,6 +1161,7 @@ impl Parser {
|
|||
winding: bool,
|
||||
in_type_args: bool,
|
||||
in_brace: bool,
|
||||
line_break: bool,
|
||||
) -> ParseResult<Expr> {
|
||||
debug_call_info!(self);
|
||||
let mut stack = Vec::<ExprOrOp>::new();
|
||||
|
@ -1167,7 +1198,7 @@ impl Parser {
|
|||
let op = self.lpop();
|
||||
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||
let t_spec = self
|
||||
.try_reduce_expr(false, in_type_args, in_brace)
|
||||
.try_reduce_expr(false, in_type_args, in_brace, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
let t_spec = Self::expr_to_type_spec(t_spec).map_err(|e| self.errs.push(e))?;
|
||||
let expr = Expr::TypeAsc(TypeAscription::new(lhs, op, t_spec));
|
||||
|
@ -1237,7 +1268,7 @@ impl Parser {
|
|||
Some(t) if t.is(Comma) && winding => {
|
||||
let first_elem = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||
let tup = self
|
||||
.try_reduce_tuple(first_elem)
|
||||
.try_reduce_tuple(first_elem, line_break)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
stack.push(ExprOrOp::Expr(Expr::Tuple(tup)));
|
||||
}
|
||||
|
@ -1348,6 +1379,15 @@ impl Parser {
|
|||
}
|
||||
Some(t) if t.is(LParen) => {
|
||||
let lparen = self.lpop();
|
||||
while self.cur_is(Newline) {
|
||||
self.skip();
|
||||
}
|
||||
let line_break = if self.cur_is(Indent) {
|
||||
self.skip();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if self.cur_is(RParen) {
|
||||
let rparen = self.lpop();
|
||||
let args = Args::new(vec![], vec![], Some((lparen, rparen)));
|
||||
|
@ -1356,8 +1396,14 @@ impl Parser {
|
|||
return Ok(Expr::Tuple(unit));
|
||||
}
|
||||
let mut expr = self
|
||||
.try_reduce_expr(true, false, false)
|
||||
.try_reduce_expr(true, false, false, line_break)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
while self.cur_is(Newline) {
|
||||
self.skip();
|
||||
}
|
||||
if self.cur_is(Dedent) {
|
||||
self.skip();
|
||||
}
|
||||
let rparen = self.lpop();
|
||||
if let Expr::Tuple(Tuple::Normal(tup)) = &mut expr {
|
||||
tup.elems.paren = Some((lparen, rparen));
|
||||
|
@ -1436,7 +1482,7 @@ impl Parser {
|
|||
Some(t) if t.is(LSqBr) && obj.col_end() == t.col_begin() => {
|
||||
let _l_sqbr = self.lpop();
|
||||
let index = self
|
||||
.try_reduce_expr(true, false, false)
|
||||
.try_reduce_expr(true, false, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
let r_sqbr = if self.cur_is(RSqBr) {
|
||||
self.lpop()
|
||||
|
@ -1556,7 +1602,7 @@ impl Parser {
|
|||
debug_call_info!(self);
|
||||
let op = self.lpop();
|
||||
let expr = self
|
||||
.try_reduce_expr(false, false, false)
|
||||
.try_reduce_expr(false, false, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(UnaryOp::new(op, expr))
|
||||
|
@ -1856,7 +1902,7 @@ impl Parser {
|
|||
return Ok(dict);
|
||||
}
|
||||
let key = self
|
||||
.try_reduce_expr(false, false, true)
|
||||
.try_reduce_expr(false, false, true, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
if self.cur_is(Colon) {
|
||||
self.skip();
|
||||
|
@ -1889,7 +1935,7 @@ impl Parser {
|
|||
if self.cur_is(Semi) {
|
||||
self.skip();
|
||||
let len = self
|
||||
.try_reduce_expr(false, false, false)
|
||||
.try_reduce_expr(false, false, false, false)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
let r_brace = self.lpop();
|
||||
return Ok(Set::WithLength(SetWithLength::new(
|
||||
|
@ -1947,19 +1993,22 @@ impl Parser {
|
|||
Err(())
|
||||
}
|
||||
|
||||
fn try_reduce_tuple(&mut self, first_elem: Expr) -> ParseResult<Tuple> {
|
||||
fn try_reduce_tuple(&mut self, first_elem: Expr, line_break: bool) -> ParseResult<Tuple> {
|
||||
debug_call_info!(self);
|
||||
let mut args = Args::new(vec![PosArg::new(first_elem)], vec![], None);
|
||||
loop {
|
||||
match self.peek() {
|
||||
Some(t) if t.is(Comma) => {
|
||||
self.skip();
|
||||
while self.cur_is(Newline) && line_break {
|
||||
self.skip();
|
||||
}
|
||||
if self.cur_is(Comma) {
|
||||
self.level -= 1;
|
||||
let err = self.skip_and_throw_syntax_err(caused_by!());
|
||||
self.errs.push(err);
|
||||
return Err(());
|
||||
} else if self.cur_is(RParen) {
|
||||
} else if self.cur_is(Dedent) || self.cur_is(RParen) {
|
||||
break;
|
||||
}
|
||||
match self.try_reduce_arg(false).map_err(|_| self.stack_dec())? {
|
||||
|
@ -2916,6 +2965,13 @@ impl Parser {
|
|||
Err(err)
|
||||
}
|
||||
}
|
||||
Expr::Lit(lit) => {
|
||||
let mut err = ParseError::simple_syntax_error(line!() as usize, lit.loc());
|
||||
if lit.is(TokenKind::NoneLit) {
|
||||
err.set_hint("you mean: `NoneType`?");
|
||||
}
|
||||
Err(err)
|
||||
}
|
||||
other => {
|
||||
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
|
||||
Err(err)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
math = pyimport "math"
|
||||
sys = pyimport "sys"
|
||||
sub = pyimport "subprocess"
|
||||
|
||||
print! math.pi
|
||||
discard sub.run! ["echo", "hello"], shell := True
|
||||
sys.exit 111
|
||||
|
|
|
@ -2,13 +2,15 @@ use std::path::PathBuf;
|
|||
|
||||
use erg_common::config::ErgConfig;
|
||||
use erg_common::error::MultiErrorDisplay;
|
||||
use erg_common::traits::Runnable;
|
||||
use erg_common::traits::{Runnable, Stream};
|
||||
|
||||
use erg_compiler::error::CompileErrors;
|
||||
|
||||
use erg::dummy::DummyVM;
|
||||
|
||||
#[test]
|
||||
fn exec_addition() -> Result<(), ()> {
|
||||
expect_failure("tests/addition.er")
|
||||
expect_failure("tests/addition.er", 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -63,7 +65,7 @@ fn exec_infer_trait() -> Result<(), ()> {
|
|||
|
||||
#[test]
|
||||
fn exec_move_check() -> Result<(), ()> {
|
||||
expect_failure("examples/move_check.er")
|
||||
expect_failure("examples/move_check.er", 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -89,17 +91,17 @@ fn exec_record() -> Result<(), ()> {
|
|||
|
||||
#[test]
|
||||
fn exec_set() -> Result<(), ()> {
|
||||
expect_failure("examples/set.er")
|
||||
expect_failure("examples/set.er", 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_side_effect() -> Result<(), ()> {
|
||||
expect_failure("examples/side_effect.er")
|
||||
expect_failure("examples/side_effect.er", 4)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_subtyping() -> Result<(), ()> {
|
||||
expect_failure("tests/subtyping.er")
|
||||
expect_failure("tests/subtyping.er", 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -128,9 +130,7 @@ fn exec_with() -> Result<(), ()> {
|
|||
}
|
||||
|
||||
fn expect_success(file_path: &'static str) -> Result<(), ()> {
|
||||
let cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
|
||||
let mut vm = DummyVM::new(cfg);
|
||||
match vm.exec() {
|
||||
match exec_vm(file_path) {
|
||||
Ok(0) => Ok(()),
|
||||
Ok(i) => {
|
||||
println!("err: end with {i}");
|
||||
|
@ -144,9 +144,7 @@ fn expect_success(file_path: &'static str) -> Result<(), ()> {
|
|||
}
|
||||
|
||||
fn expect_end_with(file_path: &'static str, code: i32) -> Result<(), ()> {
|
||||
let cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
|
||||
let mut vm = DummyVM::new(cfg);
|
||||
match vm.exec() {
|
||||
match exec_vm(file_path) {
|
||||
Ok(0) => Err(()),
|
||||
Ok(i) => {
|
||||
if i == code {
|
||||
|
@ -163,15 +161,41 @@ fn expect_end_with(file_path: &'static str, code: i32) -> Result<(), ()> {
|
|||
}
|
||||
}
|
||||
|
||||
fn expect_failure(file_path: &'static str) -> Result<(), ()> {
|
||||
let cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
|
||||
let mut vm = DummyVM::new(cfg);
|
||||
match vm.exec() {
|
||||
fn expect_failure(file_path: &'static str, errs_len: usize) -> Result<(), ()> {
|
||||
match exec_vm(file_path) {
|
||||
Ok(0) => Err(()),
|
||||
Ok(_) => Ok(()),
|
||||
Err(errs) => {
|
||||
errs.fmt_all_stderr();
|
||||
if errs.len() == errs_len {
|
||||
Ok(())
|
||||
} else {
|
||||
println!("err: error length is not {errs_len} but {}", errs.len());
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _exec_vm(file_path: &'static str) -> Result<i32, CompileErrors> {
|
||||
let cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
|
||||
let mut vm = DummyVM::new(cfg);
|
||||
vm.exec()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn exec_vm(file_path: &'static str) -> Result<i32, CompileErrors> {
|
||||
const STACK_SIZE: usize = 4 * 1024 * 1024;
|
||||
|
||||
let child = std::thread::Builder::new()
|
||||
.stack_size(STACK_SIZE)
|
||||
.spawn(move || _exec_vm(file_path))
|
||||
.unwrap();
|
||||
// Wait for thread to join
|
||||
child.join().unwrap()
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn exec_vm(file_path: &'static str) -> Result<i32, CompileErrors> {
|
||||
_exec_vm(file_path)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue