diff --git a/README.md b/README.md index f70cee36..a736c6cd 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@

Build status Build status +
+ + +
日本語 | 简体中文 | 繁體中文

diff --git a/README_JA.md b/README_JA.md index e27c472c..091e3e8d 100644 --- a/README_JA.md +++ b/README_JA.md @@ -10,6 +10,9 @@ Build status Build status
+ + +

[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3D6558d5ca162c97da7baa29d659f0f425fa8fdd3d) diff --git a/README_zh-CN.md b/README_zh-CN.md index e9933928..8352037c 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -10,6 +10,9 @@ Build status Build status
+ + +

[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3D6558d5ca162c97da7baa29d659f0f425fa8fdd3d) diff --git a/README_zh-TW.md b/README_zh-TW.md index 6258b25b..b05728f9 100644 --- a/README_zh-TW.md +++ b/README_zh-TW.md @@ -10,6 +10,9 @@ Build status Build status
+ + +

[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3D6558d5ca162c97da7baa29d659f0f425fa8fdd3d) diff --git a/compiler/erg_common/astr.rs b/compiler/erg_common/astr.rs deleted file mode 100644 index df65cbbe..00000000 --- a/compiler/erg_common/astr.rs +++ /dev/null @@ -1,181 +0,0 @@ -use std::borrow::Borrow; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::ops::{Add, Deref}; - -use crate::style::{StyledString, StyledStrings}; -use crate::Str; - -pub type ArcStr = std::sync::Arc; - -/// Used to hold an immutable string. -/// -/// It can construct as a const (by AtomicStr::ever). -#[derive(Debug, Clone, Eq)] -pub enum AtomicStr { - Arc(ArcStr), - Static(&'static str), -} - -// unsafe impl Sync for AtomicStr {} - -impl PartialEq for AtomicStr { - #[inline] - fn eq(&self, other: &AtomicStr) -> bool { - self[..] == other[..] - } -} - -impl Add<&str> for AtomicStr { - type Output = AtomicStr; - #[inline] - fn add(self, other: &str) -> AtomicStr { - AtomicStr::from(&format!("{self}{other}")) - } -} - -impl Hash for AtomicStr { - fn hash(&self, state: &mut H) { - match self { - AtomicStr::Arc(s) => s[..].hash(state), - AtomicStr::Static(s) => (*s).hash(state), - } - } -} - -impl fmt::Display for AtomicStr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - AtomicStr::Arc(s) => write!(f, "{s}"), - AtomicStr::Static(s) => write!(f, "{s}"), - } - } -} - -// &'static str -> &strになってしまわないように -// あえて`impl> From for AtomicStr { ... }`はしない -impl From<&'static str> for AtomicStr { - #[inline] - fn from(s: &'static str) -> Self { - AtomicStr::ever(s) - } -} - -impl From<&String> for AtomicStr { - #[inline] - fn from(s: &String) -> Self { - AtomicStr::Arc((s[..]).into()) - } -} - -impl From for AtomicStr { - #[inline] - fn from(s: String) -> Self { - AtomicStr::Arc((s[..]).into()) - } -} - -impl From<&ArcStr> for AtomicStr { - #[inline] - fn from(s: &ArcStr) -> Self { - AtomicStr::Arc(s.clone()) - } -} - -impl From for AtomicStr { - #[inline] - fn from(s: ArcStr) -> Self { - AtomicStr::Arc(s) - } -} - -impl From<&AtomicStr> for AtomicStr { - #[inline] - fn from(s: &AtomicStr) -> Self { - match s { - AtomicStr::Arc(s) => AtomicStr::Arc(s.clone()), - AtomicStr::Static(s) => AtomicStr::Static(s), - } - } -} - -impl From for AtomicStr { - #[inline] - fn from(s: Str) -> Self { - match s { - Str::Rc(s) => AtomicStr::Arc((&s[..]).into()), - Str::Static(s) => AtomicStr::Static(s), - } - } -} - -impl From<&Str> for AtomicStr { - #[inline] - fn from(s: &Str) -> Self { - match s { - Str::Rc(s) => AtomicStr::Arc((&s[..]).into()), - Str::Static(s) => AtomicStr::Static(s), - } - } -} - -impl From for AtomicStr { - #[inline] - fn from(s: StyledString) -> Self { - AtomicStr::Arc(s.to_string().into()) - } -} - -impl From for AtomicStr { - #[inline] - fn from(s: StyledStrings) -> Self { - AtomicStr::Arc(s.to_string().into()) - } -} - -impl Deref for AtomicStr { - type Target = str; - fn deref(&self) -> &Self::Target { - self.borrow() - } -} - -impl Borrow for AtomicStr { - #[inline] - fn borrow(&self) -> &str { - match self { - AtomicStr::Arc(s) => s.borrow(), - AtomicStr::Static(s) => s, - } - } -} - -impl AsRef for AtomicStr { - fn as_ref(&self) -> &str { - self.borrow() - } -} - -impl AtomicStr { - pub const fn ever(s: &'static str) -> Self { - AtomicStr::Static(s) - } - - pub fn arc(s: &str) -> Self { - AtomicStr::Arc(s.into()) - } - - pub fn into_rc(self) -> ArcStr { - match self { - AtomicStr::Arc(s) => s, - AtomicStr::Static(s) => ArcStr::from(s), - } - } - - pub fn is_uppercase(&self) -> bool { - self.chars() - .next() - .map(|c| c.is_uppercase()) - .unwrap_or(false) - } -} diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index f60189cf..bee93dd0 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -5,7 +5,6 @@ use std::cmp; use std::fmt; use std::io::{stderr, BufWriter, Write as _}; -use crate::astr::AtomicStr; use crate::config::Input; use crate::style::Attribute; use crate::style::Characters; @@ -25,95 +24,95 @@ use crate::{impl_display_from_debug, switch_lang}; pub enum ErrorKind { /* compile errors */ AssignError = 0, - AttributeError, - BytecodeError, - CompilerSystemError, - EnvironmentError, - FeatureError, - ImportError, - IndentationError, - NameError, - NotImplementedError, - PatternError, - SyntaxError, - TabError, - TypeError, - UnboundLocalError, - PurityError, - HasEffect, - MoveError, - NotConstExpr, - InheritanceError, - VisibilityError, - MethodError, - DummyError, + AttributeError = 1, + BytecodeError = 2, + CompilerSystemError = 3, + EnvironmentError = 4, + FeatureError = 5, + ImportError = 6, + IndentationError = 7, + NameError = 8, + NotImplementedError = 9, + PatternError = 10, + SyntaxError = 11, + TabError = 12, + TypeError = 13, + UnboundLocalError = 14, + PurityError = 15, + HasEffect = 16, + MoveError = 17, + NotConstExpr = 18, + InheritanceError = 19, + VisibilityError = 20, + MethodError = 21, + DummyError = 22, /* compile warnings */ AttributeWarning = 60, - CastWarning, - DeprecationWarning, - FutureWarning, - ImportWarning, - PendingDeprecationWarning, - SyntaxWarning, - TypeWarning, - NameWarning, - UnusedWarning, - Warning, + CastWarning = 61, + DeprecationWarning = 62, + FutureWarning = 63, + ImportWarning = 64, + PendingDeprecationWarning = 65, + SyntaxWarning = 66, + TypeWarning = 67, + NameWarning = 68, + UnusedWarning = 69, + Warning = 70, /* runtime errors */ ArithmeticError = 100, - AssertionError, - BlockingIOError, - BrokenPipeError, - BufferError, - ChildProcessError, - ConnectionAbortedError, - ConnectionError, - ConnectionRefusedError, - ConnectionResetError, - EOFError, - FileExistsError, - FileNotFoundError, - IndexError, - InterruptedError, - IoError, - IsADirectoryError, - KeyError, - LookupError, - MemoryError, - ModuleNotFoundError, - NotADirectoryError, - OSError, - OverflowError, - PermissionError, - ProcessLookupError, - RecursionError, - ReferenceError, - RuntimeAttributeError, - RuntimeError, - RuntimeTypeError, - RuntimeUnicodeError, - TimeoutError, - UnicodeError, - UserError, - ValueError, - VMSystemError, - WindowsError, - ZeroDivisionError, + AssertionError = 101, + BlockingIOError = 102, + BrokenPipeError = 103, + BufferError = 104, + ChildProcessError = 105, + ConnectionAbortedError = 106, + ConnectionError = 107, + ConnectionRefusedError = 108, + ConnectionResetError = 109, + EOFError = 110, + FileExistsError = 111, + FileNotFoundError = 112, + IndexError = 113, + InterruptedError = 114, + IoError = 115, + IsADirectoryError = 116, + KeyError = 117, + LookupError = 118, + MemoryError = 119, + ModuleNotFoundError = 120, + NotADirectoryError = 121, + OSError = 122, + OverflowError = 123, + PermissionError = 124, + ProcessLookupError = 125, + RecursionError = 126, + ReferenceError = 127, + RuntimeAttributeError = 128, + RuntimeError = 129, + RuntimeTypeError = 130, + RuntimeUnicodeError = 131, + TimeoutError = 132, + UnicodeError = 133, + UserError = 134, + ValueError = 135, + VMSystemError = 136, + WindowsError = 137, + ZeroDivisionError = 138, /* runtime warnings */ BytesWarning = 180, - ResourceWarning, - RuntimeWarning, - UnicodeWarning, - UserWarning, + ResourceWarning = 181, + RuntimeWarning = 182, + UnicodeWarning = 183, + UserWarning = 184, /* exceptions */ BaseException = 200, - Exception, - GeneratorExit, - KeyboardInterrupt, - StopAsyncIteration, - StopIteration, - SystemExit, - UserException, + Exception = 201, + GeneratorExit = 202, + KeyboardInterrupt = 203, + StopAsyncIteration = 204, + StopIteration = 205, + SystemExit = 206, + UserException = 207, } use ErrorKind::*; @@ -327,8 +326,8 @@ fn format_context( chars: &Characters, // kinds of error for specify the color mark: char, - sub_msg: &[AtomicStr], - hint: Option<&AtomicStr>, + sub_msg: &[String], + hint: Option<&String>, ) -> String { let mark = mark.to_string(); let codes = if e.input().is_repl() { @@ -388,12 +387,12 @@ fn format_context( #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct SubMessage { pub loc: Location, - msg: Vec, - hint: Option, + msg: Vec, + hint: Option, } impl SubMessage { - pub fn ambiguous_new(loc: Location, msg: Vec, hint: Option) -> Self { + pub fn ambiguous_new(loc: Location, msg: Vec, hint: Option) -> Self { Self { loc, msg, hint } } @@ -405,11 +404,11 @@ impl SubMessage { } } - pub fn set_hint>(&mut self, hint: S) { + pub fn set_hint>(&mut self, hint: S) { self.hint = Some(hint.into()); } - pub fn get_hint(self) -> Option { + pub fn get_hint(self) -> Option { self.hint } @@ -500,7 +499,7 @@ impl SubMessage { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ErrorCore { pub sub_messages: Vec, - pub main_message: AtomicStr, + pub main_message: String, pub errno: usize, pub kind: ErrorKind, pub loc: Location, @@ -508,7 +507,7 @@ pub struct ErrorCore { } impl ErrorCore { - pub fn new>( + pub fn new>( sub_messages: Vec, main_message: S, errno: usize, diff --git a/compiler/erg_common/lib.rs b/compiler/erg_common/lib.rs index fb17b9a5..7598e73c 100644 --- a/compiler/erg_common/lib.rs +++ b/compiler/erg_common/lib.rs @@ -1,7 +1,6 @@ //! provides utilities for parser, compiler, and vm crate. use std::fmt; -pub mod astr; pub mod cache; pub mod config; pub mod datetime; diff --git a/compiler/erg_common/python_util.rs b/compiler/erg_common/python_util.rs index 4977149c..6bb144b0 100644 --- a/compiler/erg_common/python_util.rs +++ b/compiler/erg_common/python_util.rs @@ -357,6 +357,174 @@ pub const BUILTIN_PYTHON_MODS: [&str; 170] = [ "zlib", "zoneinfo", ]; +#[cfg(not(any(windows, unix)))] +pub const BUILTIN_PYTHON_MODS: [&str; 165] = [ + "abc", + "argparse", + "array", + "ast", + "asyncio", + "atexit", + "base64", + "bdb", + "binascii", + "binhex", + "bisect", + "builtins", + "bz2", + "calendar", + "cmath", + "code", + "codecs", + "codeop", + "collections", + "colorsys", + "compileall", + "concurrent", + "configparser", + "contextlib", + "contextvars", + "copy", + "copyreg", + "cProfile", + "csv", + "ctypes", + "dataclasses", + "datetime", + "dbm", + "decimal", + "difflib", + "dis", + "distutils", + "doctest", + "email", + "encodings", + "ensurepip", + "enum", + "errno", + "faulthandler", + "filecmp", + "fileinput", + "fnmatch", + "fractions", + "ftplib", + "functools", + "gc", + "getopt", + "getpass", + "gettext", + "glob", + "graphlib", + "gzip", + "hashlib", + "heapq", + "hmac", + "html", + "http", + "imaplib", + "importlib", + "inspect", + "io", + "ipaddress", + "itertools", + "json", + "keyword", + "lib2to3", + "linecache", + "locale", + "logging", + "lzma", + "mailbox", + "marshal", + "math", + "mimetypes", + "mmap", + "modulefinder", + "multiprocessing", + "netrc", + "numbers", + "operator", + "os", + "pathlib", + "pdb", + "pickle", + "pickletools", + "pkgutil", + "platform", + "plistlib", + "poplib", + "pprint", + "profile", + "pstats", + "py_compile", + "pyclbr", + "pydoc", + "queue", + "quopri", + "random", + "re", + "reprlib", + "rlcompleter", + "runpy", + "sched", + "secrets", + "select", + "selectors", + "shelve", + "shlex", + "shutil", + "signal", + "site", + "smtplib", + "socket", + "socketserver", + "sqlite3", + "ssl", + "stat", + "statistics", + "string", + "stringprep", + "struct", + "subprocess", + "symtable", + "sys", + "sysconfig", + "tabnanny", + "tarfile", + "tempfile", + "test", + "textwrap", + "threading", + "time", + "timeit", + "tkinter", + "token", + "tokenize", + "trace", + "traceback", + "tracemalloc", + "turtle", + "turtledemo", + "types", + "typing", + "unicodedata", + "unittest", + "urllib", + "uuid", + "venv", + "warnings", + "wave", + "weakref", + "webbrowser", + "wsgiref", + "xml", + "xmlrpc", + "zipapp", + "zipfile", + "zipimport", + "zlib", + "zoneinfo", +]; pub fn which_python() -> String { let (cmd, python) = if cfg!(windows) { @@ -416,6 +584,12 @@ pub struct PythonVersion { pub micro: Option, } +impl Default for PythonVersion { + fn default() -> Self { + Self::new(3, Some(11), Some(0)) + } +} + impl PythonVersion { pub const fn new(major: u8, minor: Option, micro: Option) -> Self { Self { diff --git a/compiler/erg_common/str.rs b/compiler/erg_common/str.rs index 0fc25366..425a0441 100644 --- a/compiler/erg_common/str.rs +++ b/compiler/erg_common/str.rs @@ -47,6 +47,20 @@ impl fmt::Display for Str { } } +impl From<&Str> for String { + #[inline] + fn from(s: &Str) -> Self { + s.to_string() + } +} + +impl From for String { + #[inline] + fn from(s: Str) -> Self { + s.to_string() + } +} + // &'static str -> &strになってしまわないように // あえて`impl> From for Str { ... }`はしない impl From<&'static str> for Str { diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 52c556a4..63fff6bb 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -464,6 +464,12 @@ impl std::fmt::Display for StyledStrings { } } +impl From for String { + fn from(s: StyledStrings) -> Self { + s.to_string() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/compiler/erg_common/traits.rs b/compiler/erg_common/traits.rs index 6225bfc7..10017ba6 100644 --- a/compiler/erg_common/traits.rs +++ b/compiler/erg_common/traits.rs @@ -350,7 +350,7 @@ fn is_in_the_expected_block(src: &str, lines: &str, in_block: &mut bool) -> bool /// This trait implements REPL (Read-Eval-Print-Loop) automatically /// The `exec` method is called for file input, etc. -pub trait Runnable: Sized { +pub trait Runnable: Sized + Default { type Err: ErrorDisplay; type Errs: MultiErrorDisplay; const NAME: &'static str; diff --git a/compiler/erg_common/tty.rs b/compiler/erg_common/tty.rs index 70afa5b9..0cb2fe3f 100644 --- a/compiler/erg_common/tty.rs +++ b/compiler/erg_common/tty.rs @@ -45,7 +45,7 @@ impl IsTty for S { /// returns true if this is a tty #[cfg(any(target_arch = "wasm32", target_env = "sgx"))] -impl IsTty for S { +impl IsTty for std::io::Stdin { fn is_tty(&self) -> bool { false } diff --git a/compiler/erg_compiler/build_hir.rs b/compiler/erg_compiler/build_hir.rs index c73f3116..0a4bf5df 100644 --- a/compiler/erg_compiler/build_hir.rs +++ b/compiler/erg_compiler/build_hir.rs @@ -16,7 +16,7 @@ use crate::mod_cache::SharedModuleCache; use crate::ownercheck::OwnershipChecker; /// Summarize lowering, side-effect checking, and ownership checking -#[derive(Debug)] +#[derive(Debug, Default)] pub struct HIRBuilder { lowerer: ASTLowerer, ownership_checker: OwnershipChecker, diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 90972965..18110790 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -7,7 +7,6 @@ use std::process; use crate::ty::codeobj::MakeFunctionFlags; use crate::ty::codeobj::{CodeObj, CodeObjFlags}; use crate::ty::value::GenTypeObj; -use erg_common::astr::AtomicStr; use erg_common::cache::CacheSet; use erg_common::config::{ErgConfig, Input}; use erg_common::env::erg_std_path; @@ -131,7 +130,7 @@ pub struct PyCodeGenStack(Vec); impl_stream_for_wrapper!(PyCodeGenStack, PyCodeGenUnit); -#[derive(Debug)] +#[derive(Debug, Default)] pub struct PyCodeGenerator { cfg: ErgConfig, pub(crate) py_version: PythonVersion, @@ -1265,7 +1264,7 @@ impl PyCodeGenerator { self.cfg.input.clone(), unary.op.loc(), &unary.op.inspect().clone(), - AtomicStr::from(unary.op.content), + String::from(unary.op.content), ) .write_to_stderr(); NOT_IMPLEMENTED @@ -1348,7 +1347,7 @@ impl PyCodeGenerator { self.cfg.input.clone(), binop.loc(), &binop.inspect().clone(), - AtomicStr::from(binop.content), + String::from(binop.content), ) .write_to_stderr(); Opcode310::NOT_IMPLEMENTED @@ -1416,7 +1415,7 @@ impl PyCodeGenerator { self.cfg.input.clone(), binop.loc(), &binop.inspect().clone(), - AtomicStr::from(binop.content), + String::from(binop.content), ) .write_to_stderr(); Opcode311::NOT_IMPLEMENTED diff --git a/compiler/erg_compiler/compile.rs b/compiler/erg_compiler/compile.rs index 6eda4532..86117c80 100644 --- a/compiler/erg_compiler/compile.rs +++ b/compiler/erg_compiler/compile.rs @@ -91,7 +91,7 @@ impl AccessKind { } /// Generates a `CodeObj` from an String or other File inputs. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Compiler { pub cfg: ErgConfig, builder: HIRBuilder, diff --git a/compiler/erg_compiler/context/hint.rs b/compiler/erg_compiler/context/hint.rs index a43fbea7..63a459e1 100644 --- a/compiler/erg_compiler/context/hint.rs +++ b/compiler/erg_compiler/context/hint.rs @@ -1,4 +1,3 @@ -use erg_common::astr::AtomicStr; use erg_common::enum_unwrap; use crate::ty::typaram::TyParam; @@ -26,11 +25,7 @@ impl Context { } } - pub(crate) fn get_type_mismatch_hint( - &self, - expected: &Type, - found: &Type, - ) -> Option { + pub(crate) fn get_type_mismatch_hint(&self, expected: &Type, found: &Type) -> Option { let expected = if let Type::FreeVar(fv) = expected { if fv.is_linked() { fv.crack().clone() @@ -42,12 +37,12 @@ impl Context { expected.clone() }; match (&expected.qual_name()[..], &found.qual_name()[..]) { - ("Eq", "Float") => Some(AtomicStr::ever("Float has no equivalence relation defined. you should use `l - r <= Float.EPSILON` instead of `l == r`.")), + ("Eq", "Float") => Some(String::from("Float has no equivalence relation defined. you should use `l - r <= Float.EPSILON` instead of `l == r`.")), _ => None, } } - pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option { + pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option { match proj { Type::Proj { lhs, rhs: _ } => { if let Type::FreeVar(fv) = lhs.as_ref() { @@ -69,9 +64,7 @@ impl Context { } else { (sup, sub) }; - Some(AtomicStr::from(format!( - "cannot {verb} {l} {preposition} {r}" - ))) + Some(format!("cannot {verb} {l} {preposition} {r}")) } else { None } diff --git a/compiler/erg_compiler/context/initialize/const_func.rs b/compiler/erg_compiler/context/initialize/const_func.rs index cd814e20..6b707d8b 100644 --- a/compiler/erg_compiler/context/initialize/const_func.rs +++ b/compiler/erg_compiler/context/initialize/const_func.rs @@ -6,7 +6,6 @@ use crate::context::Context; use crate::ty::constructors::{and, mono}; use crate::ty::value::{EvalValueResult, GenTypeObj, TypeObj, ValueObj}; use crate::ty::ValueArgs; -use erg_common::astr::AtomicStr; use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage}; use erg_common::style::{Color, StyledStr, StyledString, THEME}; @@ -24,7 +23,7 @@ pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult EvalValueResult EvalValueResult EvalValueResult< let class = args.remove_left_or_key("Class").ok_or_else(|| { ErrorCore::new( vec![SubMessage::only_loc(Location::Unknown)], - AtomicStr::from(format!("{CLASS_ERR} is not passed")), + format!("{CLASS_ERR} is not passed"), line!() as usize, ErrorKind::KeyError, Location::Unknown, @@ -120,7 +119,7 @@ pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult EvalValueResult EvalValueResult EvalValueResult< } else { Err(ErrorCore::new( vec![SubMessage::only_loc(Location::Unknown)], - AtomicStr::from(format!( + format!( "[{}] has {} elements, but accessed {}th element", erg_common::fmt_vec(&slf), slf.len(), index - )), + ), line!() as usize, ErrorKind::IndexError, Location::Unknown, @@ -226,7 +225,7 @@ pub fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult } else { Err(ErrorCore::new( vec![SubMessage::only_loc(Location::Unknown)], - AtomicStr::from(format!("Index out of range: {}", index)), + format!("Index out of range: {}", index), line!() as usize, ErrorKind::IndexError, Location::Unknown, diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index 8cd19d63..d01b579b 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -921,6 +921,12 @@ impl Context { Immutable, Public, ); + str_.register_builtin_impl( + "format", + fn_met(Str, vec![], Some(kw("args", Obj)), vec![], Str), + Immutable, + Public, + ); let mut str_eq = Self::builtin_methods(Some(mono("Eq")), 2); str_eq.register_builtin_impl("__eq__", fn1_met(Str, Str, Bool), Const, Public); str_.register_trait(Str, str_eq); diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index 6bb3ef67..0b29264c 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -18,7 +18,6 @@ use std::mem; use std::option::Option; // conflicting to Type::Option use std::path::Path; -use erg_common::astr::AtomicStr; use erg_common::config::ErgConfig; use erg_common::dict::Dict; use erg_common::error::Location; @@ -792,8 +791,8 @@ impl Context { } #[inline] - pub fn caused_by(&self) -> AtomicStr { - AtomicStr::arc(&self.name[..]) + pub fn caused_by(&self) -> String { + String::from(&self.name[..]) } pub(crate) fn get_outer(&self) -> Option<&Context> { diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 2f34dcda..2c02f260 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -1,12 +1,12 @@ +use std::fmt; use std::fmt::Display; -use erg_common::astr::AtomicStr; use erg_common::config::Input; use erg_common::error::{ ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay, SubMessage, }; use erg_common::set::Set; -use erg_common::style::{Attribute, Color, StyledStr, StyledString, StyledStrings, THEME}; +use erg_common::style::{Attribute, Color, StyledStr, StyledString, StyledStrings, Theme, THEME}; use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; use erg_common::{ @@ -113,7 +113,8 @@ pub fn readable_name(name: &str) -> &str { pub struct CompileError { pub core: Box, // ErrorCore is large, so box it pub input: Input, - pub caused_by: AtomicStr, + pub caused_by: String, + pub theme: Theme, } impl_display_and_error!(CompileError); @@ -123,7 +124,8 @@ impl From for CompileError { Self { core: Box::new(err.core), input: err.input, - caused_by: "".into(), + caused_by: "".to_owned(), + theme: THEME, } } } @@ -151,11 +153,12 @@ const URL: StyledStr = StyledStr::new( ); impl CompileError { - pub fn new(core: ErrorCore, input: Input, caused_by: AtomicStr) -> Self { + pub fn new(core: ErrorCore, input: Input, caused_by: String) -> Self { Self { core: Box::new(core), input, caused_by, + theme: THEME, } } @@ -217,7 +220,7 @@ impl CompileError { ) } - pub fn feature_error(input: Input, loc: Location, name: &str, caused_by: AtomicStr) -> Self { + pub fn feature_error(input: Input, loc: Location, name: &str, caused_by: String) -> Self { Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -300,7 +303,7 @@ impl TyCheckError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, ) -> Self { let name = readable_name(name); @@ -327,7 +330,7 @@ impl TyCheckError { errno: usize, callee: &C, param_ts: impl Iterator, - caused_by: AtomicStr, + caused_by: String, ) -> Self { let param_ts = fmt_iter(param_ts); Self::new( @@ -357,13 +360,13 @@ impl TyCheckError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, nth_param: Option, expect: &Type, found: &Type, candidates: Option>, - hint: Option, + hint: Option, ) -> Self { let ord = match nth_param { Some(pos) => switch_lang!( @@ -422,7 +425,7 @@ impl TyCheckError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, expect: &Type, found: &Type, @@ -471,7 +474,7 @@ impl TyCheckError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, t: &Type, ) -> Self { @@ -497,7 +500,7 @@ impl TyCheckError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, expect: usize, found: usize, ) -> Self { @@ -541,7 +544,7 @@ impl TyCheckError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, expr_t: &Type, ) -> Self { Self::new( @@ -566,7 +569,7 @@ impl TyCheckError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, expr: &str, ) -> Self { Self::new( @@ -601,7 +604,7 @@ impl TyCheckError { errno: usize, loc: Location, callee_name: &str, - caused_by: AtomicStr, + caused_by: String, params_len: usize, pos_args_len: usize, kw_args_len: usize, @@ -667,7 +670,7 @@ passed keyword args: {kw_args_len}" errno: usize, loc: Location, callee_name: &str, - caused_by: AtomicStr, + caused_by: String, missing_len: usize, missing_params: Vec, ) -> Self { @@ -697,7 +700,7 @@ passed keyword args: {kw_args_len}" errno: usize, loc: Location, callee_name: &str, - caused_by: AtomicStr, + caused_by: String, arg_name: &str, ) -> Self { let name = readable_name(callee_name); @@ -725,7 +728,7 @@ passed keyword args: {kw_args_len}" errno: usize, loc: Location, callee_name: &str, - caused_by: AtomicStr, + caused_by: String, param_name: &str, ) -> Self { let name = readable_name(callee_name); @@ -754,7 +757,7 @@ passed keyword args: {kw_args_len}" lhs_t: &Type, rhs_t: &Type, loc: Location, - caused_by: AtomicStr, + caused_by: String, ) -> Self { let mut lhs_typ = StyledStrings::default(); switch_lang!( @@ -800,7 +803,7 @@ passed keyword args: {kw_args_len}" lhs_t: &Type, rhs_t: &Type, loc: Location, - caused_by: AtomicStr, + caused_by: String, ) -> Self { let lhs_t = StyledString::new(&format!("{}", lhs_t), Some(WARN), Some(Attribute::Bold)); let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARN), Some(Attribute::Bold)); @@ -828,7 +831,7 @@ passed keyword args: {kw_args_len}" sub_t: &Type, sup_t: &Type, loc: Location, - caused_by: AtomicStr, + caused_by: String, ) -> Self { let mut sub_type = StyledStrings::default(); switch_lang!( @@ -875,7 +878,7 @@ passed keyword args: {kw_args_len}" errno: usize, lhs: &Predicate, rhs: &Predicate, - caused_by: AtomicStr, + caused_by: String, ) -> Self { let mut lhs_uni = StyledStrings::default(); switch_lang!( @@ -920,8 +923,8 @@ passed keyword args: {kw_args_len}" errno: usize, proj: &Type, loc: Location, - caused_by: AtomicStr, - hint: Option, + caused_by: String, + hint: Option, ) -> Self { Self::new( ErrorCore::new( @@ -947,8 +950,8 @@ passed keyword args: {kw_args_len}" class: &Type, trait_: &Type, loc: Location, - caused_by: AtomicStr, - hint: Option, + caused_by: String, + hint: Option, ) -> Self { Self::new( ErrorCore::new( @@ -972,9 +975,9 @@ passed keyword args: {kw_args_len}" input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, - hint: Option, + hint: Option, ) -> Self { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( @@ -1008,12 +1011,12 @@ passed keyword args: {kw_args_len}" input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, member_name: &str, trait_type: &Type, expect: &Type, found: &Type, - hint: Option, + hint: Option, ) -> Self { let mut expct = StyledStrings::default(); expct.push_str_with_color_and_attribute(&format!("{}", trait_type), WARN, Attribute::Bold); @@ -1059,11 +1062,11 @@ passed keyword args: {kw_args_len}" pub fn trait_member_not_defined_error( input: Input, errno: usize, - caused_by: AtomicStr, + caused_by: String, member_name: &str, trait_type: &Type, class_type: &Type, - hint: Option, + hint: Option, ) -> Self { let member_name = StyledString::new(member_name, Some(WARN), Some(Attribute::Bold)); Self::new( @@ -1088,11 +1091,11 @@ passed keyword args: {kw_args_len}" pub fn not_in_trait_error( input: Input, errno: usize, - caused_by: AtomicStr, + caused_by: String, member_name: &str, trait_type: &Type, class_type: &Type, - hint: Option, + hint: Option, ) -> Self { let member_name = StyledString::new(member_name, Some(WARN), Some(Attribute::Bold)); Self::new( @@ -1118,7 +1121,7 @@ passed keyword args: {kw_args_len}" errno: usize, name: &str, loc: Location, - caused_by: AtomicStr, + caused_by: String, ) -> Self { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( @@ -1144,7 +1147,7 @@ passed keyword args: {kw_args_len}" errno: usize, expr: &(impl Locational + Display), candidates: &[Type], - caused_by: AtomicStr, + caused_by: String, ) -> Self { let hint = Some( switch_lang!( @@ -1197,7 +1200,7 @@ pub type EvalResult = TyCheckResult; pub type SingleEvalResult = SingleTyCheckResult; impl EvalError { - pub fn not_const_expr(input: Input, errno: usize, loc: Location, caused_by: AtomicStr) -> Self { + pub fn not_const_expr(input: Input, errno: usize, loc: Location, caused_by: String) -> Self { Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1216,12 +1219,7 @@ impl EvalError { ) } - pub fn invalid_literal( - input: Input, - errno: usize, - loc: Location, - caused_by: AtomicStr, - ) -> Self { + pub fn invalid_literal(input: Input, errno: usize, loc: Location, caused_by: String) -> Self { Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1245,7 +1243,7 @@ pub type EffectError = TyCheckError; pub type EffectErrors = TyCheckErrors; impl EffectError { - pub fn has_effect>( + pub fn has_effect>( input: Input, errno: usize, expr: &Expr, @@ -1269,7 +1267,7 @@ impl EffectError { ) } - pub fn proc_assign_error>( + pub fn proc_assign_error>( input: Input, errno: usize, sig: &Signature, @@ -1307,7 +1305,7 @@ pub type OwnershipError = TyCheckError; pub type OwnershipErrors = TyCheckErrors; impl OwnershipError { - pub fn move_error>( + pub fn move_error>( input: Input, errno: usize, name: &str, @@ -1355,13 +1353,13 @@ pub type LowerResult = TyCheckResult; pub type SingleLowerResult = SingleTyCheckResult; impl LowerError { - pub fn syntax_error>( + pub fn syntax_error>( input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, desc: S, - hint: Option, + hint: Option, ) -> Self { Self::new( ErrorCore::new( @@ -1380,7 +1378,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, ) -> Self { let name = readable_name(name); @@ -1406,7 +1404,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, ) -> Self { let name = readable_name(name); @@ -1432,7 +1430,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, spec_t: &Type, found_t: &Type, @@ -1462,7 +1460,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, similar_name: Option<&str>, ) -> Self { @@ -1475,7 +1473,6 @@ impl LowerError { "traditional_chinese" => format!("存在相同名稱變量: {n}"), "english" => format!("exists a similar name variable: {n}"), ) - .into() }); let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( @@ -1500,7 +1497,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, typ: &Type, ) -> Self { let typ = StyledString::new(&typ.to_string(), Some(ERR), Some(Attribute::Bold)); @@ -1533,7 +1530,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, obj_t: &Type, name: &str, similar_name: Option<&str>, @@ -1545,7 +1542,6 @@ impl LowerError { "traditional_chinese" => format!("具有相同名稱的屬性: {n}"), "english" => format!("has a similar name attribute: {n}"), ) - .into() }); let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( @@ -1571,7 +1567,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, obj_name: &str, obj_t: &Type, name: &str, @@ -1585,7 +1581,6 @@ impl LowerError { "traditional_chinese" => format!("具有相同名稱的屬性: {n}"), "english" => format!("has a similar name attribute: {n}"), ) - .into() }); let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( @@ -1610,7 +1605,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, ) -> Self { let name = StyledString::new(readable_name(name), Some(WARN), Some(Attribute::Bold)); @@ -1637,7 +1632,7 @@ impl LowerError { errno: usize, loc: Location, name: &str, - caused_by: AtomicStr, + caused_by: String, ) -> Self { let name = StyledString::new(readable_name(name), Some(WARN), Some(Attribute::Bold)); Self::new( @@ -1658,7 +1653,7 @@ impl LowerError { ) } - pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: AtomicStr) -> Self { + pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: String) -> Self { let name = StyledString::new( readable_name(ident.inspect()), Some(WARN), @@ -1686,7 +1681,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, vis: Visibility, ) -> Self { @@ -1725,7 +1720,7 @@ impl LowerError { ) } - pub fn override_error>( + pub fn override_error>( input: Input, errno: usize, name: &str, @@ -1789,7 +1784,7 @@ impl LowerError { errno: usize, class: String, loc: Location, - caused_by: AtomicStr, + caused_by: String, ) -> Self { Self::new( ErrorCore::new( @@ -1814,8 +1809,8 @@ impl LowerError { errno: usize, desc: String, loc: Location, - caused_by: AtomicStr, - hint: Option, + caused_by: String, + hint: Option, ) -> Self { Self::new( ErrorCore::new( @@ -1835,7 +1830,7 @@ impl LowerError { errno: usize, mod_name: &str, loc: Location, - caused_by: AtomicStr, + caused_by: String, ) -> Self { let desc = switch_lang!( "japanese" => format!("{mod_name}モジュールはお使いの環境をサポートしていません"), @@ -1851,7 +1846,7 @@ impl LowerError { errno: usize, desc: String, loc: Location, - caused_by: AtomicStr, + caused_by: String, similar_erg_mod: Option, similar_py_mod: Option, ) -> Self { @@ -1948,7 +1943,6 @@ impl LowerError { } }, ); - let hint = hint.map(AtomicStr::from); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( @@ -1970,7 +1964,7 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, ) -> Self { Self::new( ErrorCore::new( @@ -1990,7 +1984,7 @@ impl LowerError { ) } - pub fn declare_error(input: Input, errno: usize, loc: Location, caused_by: AtomicStr) -> Self { + pub fn declare_error(input: Input, errno: usize, loc: Location, caused_by: String) -> Self { Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -2014,10 +2008,10 @@ impl LowerError { input: Input, errno: usize, loc: Location, - caused_by: AtomicStr, + caused_by: String, name: &str, cast_to: &Type, - hint: Option, + hint: Option, ) -> Self { let name = StyledString::new(name, Some(WARN), Some(Attribute::Bold)); let found = StyledString::new(&format!("{}", cast_to), Some(WARN), Some(Attribute::Bold)); @@ -2065,6 +2059,12 @@ impl From for CompileErrors { impl MultiErrorDisplay for CompileErrors {} +impl fmt::Display for CompileErrors { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt_all(f) + } +} + impl CompileErrors { pub fn flush(&mut self) -> Self { Self(self.0.drain(..).collect()) diff --git a/compiler/erg_compiler/lib.rs b/compiler/erg_compiler/lib.rs index d3013842..f8629da8 100644 --- a/compiler/erg_compiler/lib.rs +++ b/compiler/erg_compiler/lib.rs @@ -21,5 +21,6 @@ pub mod mod_cache; pub mod optimize; pub mod ownercheck; pub mod reorder; +pub mod transpile; pub mod ty; pub mod varinfo; diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index ac8b282c..ba73865f 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -2,7 +2,6 @@ //! //! ASTLowerer(ASTからHIRへの変換器)を実装 -use erg_common::astr::AtomicStr; use erg_common::config::ErgConfig; use erg_common::dict; use erg_common::error::{Location, MultiErrorDisplay}; @@ -161,7 +160,7 @@ impl ASTLowerer { self.cfg.input.clone(), line!() as usize, expr.loc(), - AtomicStr::arc(&self.ctx.name[..]), + String::from(&self.ctx.name[..]), switch_lang!( "japanese" => format!("式の評価結果(: {})が使われていません", expr.ref_t()), "simplified_chinese" => format!("表达式评估结果(: {})未使用", expr.ref_t()), @@ -226,7 +225,7 @@ impl ASTLowerer { self.cfg.input.clone(), line!() as usize, elem.loc(), - AtomicStr::arc(&self.ctx.name[..]), + String::from(&self.ctx.name[..]), switch_lang!( "japanese" => "配列の要素は全て同じ型である必要があります", "simplified_chinese" => "数组元素必须全部是相同类型", @@ -372,7 +371,7 @@ impl ASTLowerer { self.cfg.input.clone(), line!() as usize, elem.loc(), - AtomicStr::arc(&self.ctx.name[..]), + String::from(&self.ctx.name[..]), switch_lang!( "japanese" => "集合の要素は全て同じ型である必要があります", "simplified_chinese" => "集合元素必须全部是相同类型", @@ -404,7 +403,7 @@ impl ASTLowerer { self.cfg.input.clone(), line!() as usize, normal_set.loc(), - AtomicStr::arc(&self.ctx.name[..]), + String::arc(&self.ctx.name[..]), switch_lang!( "japanese" => "要素が重複しています", "simplified_chinese" => "元素重复", @@ -498,7 +497,7 @@ impl ASTLowerer { self.cfg.input.clone(), line!() as usize, loc, - AtomicStr::arc(&self.ctx.name[..]), + String::from(&self.ctx.name[..]), switch_lang!( "japanese" => "Dictの値は全て同じ型である必要があります", "simplified_chinese" => "Dict的值必须是同一类型", @@ -543,7 +542,7 @@ impl ASTLowerer { self.cfg.input.clone(), line!() as usize, normal_set.loc(), - AtomicStr::arc(&self.ctx.name[..]), + String::arc(&self.ctx.name[..]), switch_lang!( "japanese" => "要素が重複しています", "simplified_chinese" => "元素重复", diff --git a/compiler/erg_compiler/main.rs b/compiler/erg_compiler/main.rs index 66cd9105..cfb8190f 100644 --- a/compiler/erg_compiler/main.rs +++ b/compiler/erg_compiler/main.rs @@ -10,6 +10,7 @@ use erg_common::traits::Runnable; use erg_compiler::build_hir::HIRBuilder; use erg_compiler::lower::ASTLowerer; +use erg_compiler::transpile::Transpiler; use erg_compiler::ty::deserialize::Deserializer; use erg_compiler::Compiler; @@ -31,6 +32,9 @@ fn run() { "check" => { HIRBuilder::run(cfg); } + "transpile" => { + Transpiler::run(cfg); + } "compile" | "exec" => { Compiler::run(cfg); } diff --git a/compiler/erg_compiler/transpile.rs b/compiler/erg_compiler/transpile.rs new file mode 100644 index 00000000..928e28f2 --- /dev/null +++ b/compiler/erg_compiler/transpile.rs @@ -0,0 +1,429 @@ +use std::fs::File; +use std::io::Write; + +use erg_common::config::ErgConfig; +use erg_common::log; +use erg_common::traits::{Runnable, Stream}; +use erg_common::Str; + +use erg_parser::ast::ParamPattern; + +use crate::build_hir::HIRBuilder; +use crate::desugar_hir::HIRDesugarer; +use crate::error::{CompileError, CompileErrors}; +use crate::hir::{ + Accessor, Array, Block, Call, ClassDef, Def, Dict, Expr, Identifier, Lambda, Params, Set, + Signature, Tuple, HIR, +}; +use crate::link::Linker; +use crate::mod_cache::SharedModuleCache; +use crate::ty::Type; + +#[derive(Debug, Clone)] +pub struct PyScript { + pub filename: Str, + pub code: String, +} + +/// Generates a `PyScript` from an String or other File inputs. +#[derive(Debug, Default)] +pub struct Transpiler { + pub cfg: ErgConfig, + builder: HIRBuilder, + mod_cache: SharedModuleCache, + script_generator: ScriptGenerator, +} + +impl Runnable for Transpiler { + type Err = CompileError; + type Errs = CompileErrors; + const NAME: &'static str = "Erg transpiler"; + + fn new(cfg: ErgConfig) -> Self { + let mod_cache = SharedModuleCache::new(); + let py_mod_cache = SharedModuleCache::new(); + Self { + builder: HIRBuilder::new_with_cache( + cfg.copy(), + "", + mod_cache.clone(), + py_mod_cache, + ), + script_generator: ScriptGenerator::new(), + mod_cache, + cfg, + } + } + + #[inline] + fn cfg(&self) -> &ErgConfig { + &self.cfg + } + + #[inline] + fn finish(&mut self) {} + + fn clear(&mut self) { + // self.builder.clear(); + } + + fn exec(&mut self) -> Result { + let path = self.input().filename().replace(".er", ".py"); + let script = self.transpile(self.input().read(), "exec")?; + let mut f = File::create(&path).unwrap(); + f.write_all(script.code.as_bytes()).unwrap(); + Ok(0) + } + + fn eval(&mut self, src: String) -> Result { + let script = self.transpile(src, "eval")?; + Ok(script.code) + } +} + +impl Transpiler { + pub fn transpile(&mut self, src: String, mode: &str) -> Result { + log!(info "the transpiling process has started."); + let hir = self.build_link_desugar(src, mode)?; + let script = self.script_generator.transpile(hir); + log!(info "code:\n{}", script.code); + log!(info "the transpiling process has completed"); + Ok(script) + } + + fn build_link_desugar(&mut self, src: String, mode: &str) -> Result { + let artifact = self + .builder + .build(src, mode) + .map_err(|artifact| artifact.errors)?; + let linker = Linker::new(&self.cfg, &self.mod_cache); + let hir = linker.link(artifact.hir); + Ok(HIRDesugarer::desugar(hir)) + } +} + +#[derive(Debug, Default)] +pub struct ScriptGenerator { + level: usize, +} + +impl ScriptGenerator { + pub const fn new() -> Self { + Self { level: 0 } + } + + pub fn transpile(&mut self, hir: HIR) -> PyScript { + let mut code = self.load_prelude(); + for chunk in hir.module.into_iter() { + code += &self.transpile_expr(chunk); + code.push('\n'); + } + PyScript { + filename: hir.name, + code, + } + } + + fn load_prelude(&mut self) -> String { + "from collections import namedtuple as NamedTuple__\n".to_string() + } + + fn transpile_expr(&mut self, expr: Expr) -> String { + match expr { + Expr::Lit(lit) => lit.token.content.to_string(), + Expr::Call(call) => self.transpile_call(call), + Expr::BinOp(bin) => { + let mut code = "(".to_string(); + code += &self.transpile_expr(*bin.lhs); + code += &bin.op.content; + code += &self.transpile_expr(*bin.rhs); + code += ")"; + code + } + Expr::UnaryOp(unary) => { + let mut code = "(".to_string(); + code += &unary.op.content; + code += &self.transpile_expr(*unary.expr); + code += ")"; + code + } + Expr::Array(array) => match array { + Array::Normal(arr) => { + let mut code = "[".to_string(); + for elem in arr.elems.pos_args { + code += &format!("{},", self.transpile_expr(elem.expr)); + } + code += "]"; + code + } + other => todo!("transpiling {other}"), + }, + Expr::Set(set) => match set { + Set::Normal(st) => { + let mut code = "{".to_string(); + for elem in st.elems.pos_args { + code += &format!("{},", self.transpile_expr(elem.expr)); + } + code += "}"; + code + } + other => todo!("transpiling {other}"), + }, + Expr::Record(rec) => { + let mut attrs = "[".to_string(); + let mut values = "(".to_string(); + for mut attr in rec.attrs.into_iter() { + attrs += &format!("'{}',", Self::transpile_ident(attr.sig.into_ident())); + if attr.body.block.len() > 1 { + todo!("transpile instant blocks") + } + values += &format!("{},", self.transpile_expr(attr.body.block.remove(0))); + } + attrs += "]"; + values += ")"; + format!("NamedTuple__('Record', {attrs}){values}") + } + Expr::Tuple(tuple) => match tuple { + Tuple::Normal(tup) => { + let mut code = "(".to_string(); + for elem in tup.elems.pos_args { + code += &format!("{},", self.transpile_expr(elem.expr)); + } + code += ")"; + code + } + }, + Expr::Dict(dict) => match dict { + Dict::Normal(dic) => { + let mut code = "{".to_string(); + for kv in dic.kvs { + code += &format!( + "({}): ({}),", + self.transpile_expr(kv.key), + self.transpile_expr(kv.value) + ); + } + code += "}"; + code + } + other => todo!("transpiling {other}"), + }, + Expr::Accessor(acc) => match acc { + Accessor::Ident(ident) => Self::transpile_ident(ident), + Accessor::Attr(attr) => { + format!( + "({}).{}", + self.transpile_expr(*attr.obj), + Self::transpile_ident(attr.ident) + ) + } + }, + Expr::Def(def) => self.transpile_def(def), + Expr::Lambda(lambda) => self.transpile_lambda(lambda), + Expr::ClassDef(classdef) => self.transpile_classdef(classdef), + Expr::AttrDef(mut adef) => { + let mut code = format!("{} = ", self.transpile_expr(Expr::Accessor(adef.attr))); + if adef.block.len() > 1 { + todo!("transpile instant blocks") + } + let expr = adef.block.remove(0); + code += &self.transpile_expr(expr); + code + } + // TODO: + Expr::Compound(comp) => { + let mut code = "".to_string(); + for expr in comp.into_iter() { + code += &self.transpile_expr(expr); + code += &format!("\n{}", " ".repeat(self.level)); + } + code + } + other => todo!("transpile {other}"), + } + } + + fn transpile_call(&mut self, mut call: Call) -> String { + match call.obj.local_name() { + Some("assert") => { + let mut code = format!("assert {}", self.transpile_expr(call.args.remove(0))); + if let Some(msg) = call.args.try_remove(0) { + code += &format!(", {}", self.transpile_expr(msg)); + } + code + } + Some("if" | "if!") => { + let cond = self.transpile_expr(call.args.remove(0)); + let Expr::Lambda(mut block) = call.args.remove(0) else { todo!() }; + let then = self.transpile_expr(block.body.remove(0)); + if let Some(Expr::Lambda(mut block)) = call.args.try_remove(0) { + let els = self.transpile_expr(block.body.remove(0)); + format!("{then} if {cond} else {els}") + } else { + format!("{then} if {cond} else None") + } + } + Some("for" | "for!") => { + let mut code = "for ".to_string(); + let iter = call.args.remove(0); + let Expr::Lambda(block) = call.args.remove(0) else { todo!() }; + let sig = block.params.non_defaults.get(0).unwrap(); + let ParamPattern::VarName(param) = &sig.pat else { todo!() }; + code += &format!("{}__ ", ¶m.token().content); + code += &format!("in {}:\n", self.transpile_expr(iter)); + code += &self.transpile_block(block.body, false); + code + } + Some("while" | "while!") => { + let mut code = "while ".to_string(); + let cond = call.args.remove(0); + let Expr::Lambda(block) = call.args.remove(0) else { todo!() }; + code += &format!("{}:\n", self.transpile_expr(cond)); + code += &self.transpile_block(block.body, false); + code + } + // TODO: + Some("match" | "match!") => { + let mut code = "match ".to_string(); + let cond = call.args.remove(0); + code += &format!("{}:\n", self.transpile_expr(cond)); + while let Some(Expr::Lambda(arm)) = call.args.try_remove(0) { + self.level += 1; + code += &" ".repeat(self.level); + let target = arm.params.non_defaults.get(0).unwrap(); + let ParamPattern::VarName(param) = &target.pat else { todo!() }; + code += &format!("case {}__:\n", ¶m.token().content); + code += &self.transpile_block(arm.body, false); + self.level -= 1; + } + code + } + _ => self.transpile_simple_call(call), + } + } + + fn transpile_simple_call(&mut self, mut call: Call) -> String { + let mut code = format!("({})", self.transpile_expr(*call.obj)); + if let Some(attr) = call.attr_name { + code += &format!(".{}", Self::transpile_ident(attr)); + } + code.push('('); + while let Some(arg) = call.args.try_remove_pos(0) { + code += &self.transpile_expr(arg.expr); + code.push(','); + } + while let Some(arg) = call.args.try_remove_kw(0) { + code += &format!("{}={},", arg.keyword, self.transpile_expr(arg.expr)); + } + code.push(')'); + code + } + + fn transpile_ident(ident: Identifier) -> String { + if let Some(py_name) = ident.vi.py_name { + py_name.to_string() + } else if ident.dot.is_some() { + ident.name.into_token().content.to_string() + } else { + let name = ident.name.into_token().content; + let name = name.replace('!', "__erg_proc__"); + let name = name.replace('$', "erg_shared__"); + format!("{name}__") + } + } + + fn transpile_params(&mut self, params: Params) -> String { + let mut code = String::new(); + for non_default in params.non_defaults { + let ParamPattern::VarName(param) = non_default.pat else { todo!() }; + code += &format!("{}__,", param.into_token().content); + } + for default in params.defaults { + let ParamPattern::VarName(param) = default.sig.pat else { todo!() }; + code += &format!( + "{}__ = {},", + param.into_token().content, + self.transpile_expr(default.default_val) + ); + } + code + } + + fn transpile_block(&mut self, block: Block, return_last: bool) -> String { + self.level += 1; + let mut code = String::new(); + let last = block.len() - 1; + for (i, chunk) in block.into_iter().enumerate() { + code += &" ".repeat(self.level); + if i == last && return_last { + code += "return "; + } + code += &self.transpile_expr(chunk); + code.push('\n'); + } + self.level -= 1; + code + } + + fn transpile_lambda(&mut self, lambda: Lambda) -> String { + let mut code = format!("(lambda {}:", self.transpile_params(lambda.params)); + if lambda.body.len() > 1 { + todo!("multi line lambda"); + } + code += &self.transpile_block(lambda.body, false); + code.pop(); // \n + code.push(')'); + code + } + + fn transpile_def(&mut self, mut def: Def) -> String { + match def.sig { + Signature::Var(var) => { + let mut code = format!("{} = ", Self::transpile_ident(var.ident)); + if def.body.block.len() > 1 { + todo!("transpile instant blocks") + } + let expr = def.body.block.remove(0); + code += &self.transpile_expr(expr); + code + } + Signature::Subr(subr) => { + let mut code = format!( + "def {}({}):\n", + Self::transpile_ident(subr.ident), + self.transpile_params(subr.params) + ); + code += &self.transpile_block(def.body.block, true); + code + } + } + } + + fn transpile_classdef(&mut self, classdef: ClassDef) -> String { + let class_name = Self::transpile_ident(classdef.sig.into_ident()); + let mut code = format!("class {class_name}():\n"); + let mut init_method = format!( + "{}def __init__(self, param__):\n", + " ".repeat(self.level + 1) + ); + match classdef.__new__.non_default_params().unwrap()[0].typ() { + Type::Record(rec) => { + for field in rec.keys() { + init_method += &format!( + "{}self.{} = param__.{}\n", + " ".repeat(self.level + 2), + field.symbol, + field.symbol + ); + } + } + other => todo!("{other}"), + } + code += &init_method; + if classdef.need_to_gen_new { + code += &format!("def new(x): return {class_name}.__call__(x)\n"); + } + code += &self.transpile_block(classdef.methods, false); + code + } +} diff --git a/compiler/erg_compiler/ty/deserialize.rs b/compiler/erg_compiler/ty/deserialize.rs index 7820205a..d2353ca7 100644 --- a/compiler/erg_compiler/ty/deserialize.rs +++ b/compiler/erg_compiler/ty/deserialize.rs @@ -2,7 +2,6 @@ use std::process; use std::string::FromUtf8Error; -use erg_common::astr::AtomicStr; use erg_common::cache::CacheSet; use erg_common::config::{ErgConfig, Input}; use erg_common::dict::Dict; @@ -21,8 +20,8 @@ use super::{HasType, Type}; #[derive(Debug)] pub struct DeserializeError { pub errno: usize, - pub caused_by: AtomicStr, - pub desc: AtomicStr, + pub caused_by: String, + pub desc: String, } impl From for DeserializeError { @@ -50,11 +49,7 @@ impl From for ErrorCore { } impl DeserializeError { - pub fn new, T: Into>( - errno: usize, - caused_by: S, - desc: T, - ) -> Self { + pub fn new, T: Into>(errno: usize, caused_by: S, desc: T) -> Self { Self { errno, caused_by: caused_by.into(), diff --git a/compiler/erg_parser/build_ast.rs b/compiler/erg_parser/build_ast.rs index 635405ec..d2a33050 100644 --- a/compiler/erg_parser/build_ast.rs +++ b/compiler/erg_parser/build_ast.rs @@ -8,6 +8,7 @@ use crate::error::{ParserRunnerError, ParserRunnerErrors}; use crate::parse::ParserRunner; /// Summarize parsing and desugaring +#[derive(Debug, Default)] pub struct ASTBuilder { runner: ParserRunner, } diff --git a/compiler/erg_parser/error.rs b/compiler/erg_parser/error.rs index 2d29857b..ab88193c 100644 --- a/compiler/erg_parser/error.rs +++ b/compiler/erg_parser/error.rs @@ -1,7 +1,8 @@ //! defines `ParseError` and others. //! //! パーサーが出すエラーを定義 -use erg_common::astr::AtomicStr; +use std::fmt; + use erg_common::config::Input; use erg_common::error::{ ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay, SubMessage, @@ -39,7 +40,7 @@ impl LexError { Self(Box::new(core)) } - pub fn set_hint>(&mut self, hint: S) { + pub fn set_hint>(&mut self, hint: S) { if let Some(sub_msg) = self.0.sub_messages.get_mut(0) { sub_msg.set_hint(hint) } @@ -95,11 +96,11 @@ impl LexError { )) } - pub fn syntax_error>( + pub fn syntax_error>( errno: usize, loc: Location, desc: S, - hint: Option, + hint: Option, ) -> Self { Self::new(ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], @@ -110,11 +111,11 @@ impl LexError { )) } - pub fn syntax_warning>( + pub fn syntax_warning>( errno: usize, loc: Location, desc: S, - hint: Option, + hint: Option, ) -> Self { Self::new(ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], @@ -139,7 +140,6 @@ impl LexError { "traditional_chinese" => format!("存在相同名稱變量: {n}"), "english" => format!("exists a similar name variable: {n}"), ) - .into() }); let name = StyledString::new(name, Some(ERR), Some(Attribute::Underline)); Self::new(ErrorCore::new( @@ -217,6 +217,12 @@ impl_stream_for_wrapper!(ParserRunnerErrors, ParserRunnerError); impl MultiErrorDisplay for ParserRunnerErrors {} +impl fmt::Display for ParserRunnerErrors { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt_all(f) + } +} + impl ParserRunnerErrors { pub fn convert(input: &Input, errs: ParseErrors) -> Self { Self( diff --git a/compiler/erg_parser/lex.rs b/compiler/erg_parser/lex.rs index dde1c872..c38abd99 100644 --- a/compiler/erg_parser/lex.rs +++ b/compiler/erg_parser/lex.rs @@ -12,6 +12,7 @@ use crate::token::{Token, TokenCategory, TokenKind, TokenStream}; use TokenKind::*; /// Lexerは使い捨てなので、Runnerを用意 +#[derive(Debug, Default)] pub struct LexerRunner { cfg: ErgConfig, } diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index a7704834..750cc454 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -164,7 +164,7 @@ impl Parser { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct ParserRunner { cfg: ErgConfig, } diff --git a/src/dummy.rs b/src/dummy.rs index a0442fe1..b132da3f 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -26,6 +26,12 @@ pub struct DummyVM { stream: Option, } +impl Default for DummyVM { + fn default() -> Self { + Self::new(ErgConfig::default()) + } +} + impl Runnable for DummyVM { type Err = EvalError; type Errs = EvalErrors; diff --git a/src/main.rs b/src/main.rs index 1d7a226e..363f2201 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ use erg_parser::ParserRunner; use erg_compiler::build_hir::HIRBuilder; use erg_compiler::lower::ASTLowerer; +use erg_compiler::transpile::Transpiler; use erg_compiler::ty::deserialize::Deserializer; use erg_compiler::Compiler; @@ -37,6 +38,9 @@ fn run() { "compile" => { Compiler::run(cfg); } + "transpile" => { + Transpiler::run(cfg); + } "exec" => { DummyVM::run(cfg); }