Merge branch 'main' of https://github.com/GreasySlug/erg into split-err-msg

This commit is contained in:
GreasySlug 2022-11-20 10:41:10 +09:00
commit ff24c62de1
31 changed files with 878 additions and 412 deletions

View file

@ -9,6 +9,10 @@
<p align='center'>
<a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a>
<a href="https://github.com/erg-lang/erg/actions/workflows/rust.yml"><img alt="Build status" src="https://github.com/erg-lang/erg/actions/workflows/rust.yml/badge.svg"></a>
<br>
<a href="https://erg-lang.org/erg-playground" data-size="large">
<img src="https://img.shields.io/static/v1?style=for-the-badge&label=&message=playground&color=green">
</a>
<br>
<a href='./README_JA.md'>日本語</a> | <a href='./README_zh-CN.md'>简体中文</a> | <a href='./README_zh-TW.md'>繁體中文</a>
</p>

View file

@ -10,6 +10,9 @@
<a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a>
<a href="https://github.com/erg-lang/erg/actions/workflows/rust.yml"><img alt="Build status" src="https://github.com/erg-lang/erg/actions/workflows/rust.yml/badge.svg"></a>
<br>
<a href="https://erg-lang.org/erg-playground" data-size="large">
<img src="https://img.shields.io/static/v1?style=for-the-badge&label=&message=playground&color=green">
</a>
</p>
[![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)

View file

@ -10,6 +10,9 @@
<a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a>
<a href="https://github.com/erg-lang/erg/actions/workflows/rust.yml"><img alt="Build status" src="https://github.com/erg-lang/erg/actions/workflows/rust.yml/badge.svg"></a>
<br>
<a href="https://erg-lang.org/erg-playground" data-size="large">
<img src="https://img.shields.io/static/v1?style=for-the-badge&label=&message=playground&color=green">
</a>
</p>
[![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)

View file

@ -10,6 +10,9 @@
<a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a>
<a href="https://github.com/erg-lang/erg/actions/workflows/rust.yml"><img alt="Build status" src="https://github.com/erg-lang/erg/actions/workflows/rust.yml/badge.svg"></a>
<br>
<a href="https://erg-lang.org/erg-playground" data-size="large">
<img src="https://img.shields.io/static/v1?style=for-the-badge&label=&message=playground&color=green">
</a>
</p>
[![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)

View file

@ -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<str>;
/// 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<H: Hasher>(&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<S: Into<Str>> From<S> 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<String> 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<ArcStr> 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<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<&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<StyledString> for AtomicStr {
#[inline]
fn from(s: StyledString) -> Self {
AtomicStr::Arc(s.to_string().into())
}
}
impl From<StyledStrings> 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<str> for AtomicStr {
#[inline]
fn borrow(&self) -> &str {
match self {
AtomicStr::Arc(s) => s.borrow(),
AtomicStr::Static(s) => s,
}
}
}
impl AsRef<str> 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)
}
}

View file

@ -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<E: ErrorDisplay + ?Sized>(
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<E: ErrorDisplay + ?Sized>(
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SubMessage {
pub loc: Location,
msg: Vec<AtomicStr>,
hint: Option<AtomicStr>,
msg: Vec<String>,
hint: Option<String>,
}
impl SubMessage {
pub fn ambiguous_new(loc: Location, msg: Vec<AtomicStr>, hint: Option<AtomicStr>) -> Self {
pub fn ambiguous_new(loc: Location, msg: Vec<String>, hint: Option<String>) -> Self {
Self { loc, msg, hint }
}
@ -405,11 +404,11 @@ impl SubMessage {
}
}
pub fn set_hint<S: Into<AtomicStr>>(&mut self, hint: S) {
pub fn set_hint<S: Into<String>>(&mut self, hint: S) {
self.hint = Some(hint.into());
}
pub fn get_hint(self) -> Option<AtomicStr> {
pub fn get_hint(self) -> Option<String> {
self.hint
}
@ -500,7 +499,7 @@ impl SubMessage {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ErrorCore {
pub sub_messages: Vec<SubMessage>,
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<S: Into<AtomicStr>>(
pub fn new<S: Into<String>>(
sub_messages: Vec<SubMessage>,
main_message: S,
errno: usize,

View file

@ -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;

View file

@ -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<u8>,
}
impl Default for PythonVersion {
fn default() -> Self {
Self::new(3, Some(11), Some(0))
}
}
impl PythonVersion {
pub const fn new(major: u8, minor: Option<u8>, micro: Option<u8>) -> Self {
Self {

View file

@ -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<Str> for String {
#[inline]
fn from(s: Str) -> Self {
s.to_string()
}
}
// &'static str -> &strになってしまわないように
// あえて`impl<S: Into<Str>> From<S> for Str { ... }`はしない
impl From<&'static str> for Str {

View file

@ -464,6 +464,12 @@ impl std::fmt::Display for StyledStrings {
}
}
impl From<StyledStrings> for String {
fn from(s: StyledStrings) -> Self {
s.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -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<Self::Err>;
const NAME: &'static str;

View file

@ -45,7 +45,7 @@ impl<S: AsRawFd> IsTty for S {
/// returns true if this is a tty
#[cfg(any(target_arch = "wasm32", target_env = "sgx"))]
impl<S: AsRawFd> IsTty for S {
impl IsTty for std::io::Stdin {
fn is_tty(&self) -> bool {
false
}

View file

@ -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,

View file

@ -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<PyCodeGenUnit>);
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

View file

@ -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,

View file

@ -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<AtomicStr> {
pub(crate) fn get_type_mismatch_hint(&self, expected: &Type, found: &Type) -> Option<String> {
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<AtomicStr> {
pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option<String> {
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
}

View file

@ -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<ValueOb
let require = args.remove_left_or_key("Requirement").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{REQ_ERR} is not passed")),
format!("{REQ_ERR} is not passed"),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -34,9 +33,9 @@ pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
let require = StyledString::new(&format!("{}", require), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"non-type object {require} is passed to {REQ_WARN}",
)),
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -54,7 +53,7 @@ pub fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
let sup = StyledStr::new("Super", Some(ERR), None);
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{sup} is not passed")),
format!("{sup} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
@ -64,9 +63,9 @@ pub fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
let sup_ty = StyledString::new(&format!("{}", sup), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"non-class object {sup_ty} is passed to {SUP_WARN}",
)),
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -88,7 +87,7 @@ pub fn inheritable_func(mut args: ValueArgs, _ctx: &Context) -> 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<ValueOb
let require = args.remove_left_or_key("Requirement").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{REQ_ERR} is not passed")),
format!("{REQ_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
@ -130,9 +129,9 @@ pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
let require = StyledString::new(&format!("{}", require), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"non-type object {require} is passed to {REQ_WARN}",
)),
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -149,7 +148,7 @@ pub fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
let sup = args.remove_left_or_key("Super").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{SUP_ERR} is not passed")),
format!("{SUP_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
@ -159,9 +158,9 @@ pub fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
let sup = StyledString::new(&format!("{}", sup), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"non-trait object {sup} is passed to {SUP_WARN}",
)),
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -187,12 +186,12 @@ pub fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> 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<V
} else {
Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{slf} has no key {index}",)),
format!("{slf} has no key {index}"),
line!() as usize,
ErrorKind::IndexError,
Location::Unknown,
@ -251,7 +250,7 @@ pub fn __range_getitem__(mut args: ValueArgs, _ctx: &Context) -> 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,

View file

@ -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);

View file

@ -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> {

View file

@ -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>, // 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<ParserRunnerError> 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<Item = &'a Type>,
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<usize>,
expect: &Type,
found: &Type,
candidates: Option<Set<Type>>,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> 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<Str>,
) -> 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<AtomicStr>,
caused_by: String,
hint: Option<String>,
) -> 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<AtomicStr>,
caused_by: String,
hint: Option<String>,
) -> 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<AtomicStr>,
hint: Option<String>,
) -> 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<AtomicStr>,
hint: Option<String>,
) -> 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<AtomicStr>,
hint: Option<String>,
) -> 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<AtomicStr>,
hint: Option<String>,
) -> 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<T> = TyCheckResult<T>;
pub type SingleEvalResult<T> = SingleTyCheckResult<T>;
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<S: Into<AtomicStr>>(
pub fn has_effect<S: Into<String>>(
input: Input,
errno: usize,
expr: &Expr,
@ -1269,7 +1267,7 @@ impl EffectError {
)
}
pub fn proc_assign_error<S: Into<AtomicStr>>(
pub fn proc_assign_error<S: Into<String>>(
input: Input,
errno: usize,
sig: &Signature,
@ -1307,7 +1305,7 @@ pub type OwnershipError = TyCheckError;
pub type OwnershipErrors = TyCheckErrors;
impl OwnershipError {
pub fn move_error<S: Into<AtomicStr>>(
pub fn move_error<S: Into<String>>(
input: Input,
errno: usize,
name: &str,
@ -1355,13 +1353,13 @@ pub type LowerResult<T> = TyCheckResult<T>;
pub type SingleLowerResult<T> = SingleTyCheckResult<T>;
impl LowerError {
pub fn syntax_error<S: Into<AtomicStr>>(
pub fn syntax_error<S: Into<String>>(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
desc: S,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> 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<S: Into<AtomicStr>>(
pub fn override_error<S: Into<String>>(
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<AtomicStr>,
caused_by: String,
hint: Option<String>,
) -> 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<Str>,
similar_py_mod: Option<Str>,
) -> 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<AtomicStr>,
hint: Option<String>,
) -> 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<CompileError> for CompileErrors {
impl MultiErrorDisplay<CompileError> 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())

View file

@ -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;

View file

@ -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" => "元素重复",

View file

@ -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);
}

View file

@ -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(),
"<module>",
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<i32, Self::Errs> {
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<String, CompileErrors> {
let script = self.transpile(src, "eval")?;
Ok(script.code)
}
}
impl Transpiler {
pub fn transpile(&mut self, src: String, mode: &str) -> Result<PyScript, CompileErrors> {
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<HIR, CompileErrors> {
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!("{}__ ", &param.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", &param.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
}
}

View file

@ -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<std::io::Error> for DeserializeError {
@ -50,11 +49,7 @@ impl From<DeserializeError> for ErrorCore {
}
impl DeserializeError {
pub fn new<S: Into<AtomicStr>, T: Into<AtomicStr>>(
errno: usize,
caused_by: S,
desc: T,
) -> Self {
pub fn new<S: Into<String>, T: Into<String>>(errno: usize, caused_by: S, desc: T) -> Self {
Self {
errno,
caused_by: caused_by.into(),

View file

@ -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,
}

View file

@ -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<S: Into<AtomicStr>>(&mut self, hint: S) {
pub fn set_hint<S: Into<String>>(&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<S: Into<AtomicStr>>(
pub fn syntax_error<S: Into<String>>(
errno: usize,
loc: Location,
desc: S,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> Self {
Self::new(ErrorCore::new(
vec![SubMessage::ambiguous_new(loc, vec![], hint)],
@ -110,11 +111,11 @@ impl LexError {
))
}
pub fn syntax_warning<S: Into<AtomicStr>>(
pub fn syntax_warning<S: Into<String>>(
errno: usize,
loc: Location,
desc: S,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> 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<ParserRunnerError> 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(

View file

@ -12,6 +12,7 @@ use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
use TokenKind::*;
/// Lexerは使い捨てなので、Runnerを用意
#[derive(Debug, Default)]
pub struct LexerRunner {
cfg: ErgConfig,
}

View file

@ -164,7 +164,7 @@ impl Parser {
}
}
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct ParserRunner {
cfg: ErgConfig,
}

View file

@ -26,6 +26,12 @@ pub struct DummyVM {
stream: Option<TcpStream>,
}
impl Default for DummyVM {
fn default() -> Self {
Self::new(ErgConfig::default())
}
}
impl Runnable for DummyVM {
type Err = EvalError;
type Errs = EvalErrors;

View file

@ -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);
}