Skip to content

Commit

Permalink
Merge pull request #91 from erg-lang/array-tuple-access
Browse files Browse the repository at this point in the history
Implement access to array/tuple elements
  • Loading branch information
mtshiba authored Aug 29, 2022
2 parents 1055e80 + 99ffee3 commit b36b400
Show file tree
Hide file tree
Showing 13 changed files with 504 additions and 405 deletions.
1 change: 1 addition & 0 deletions compiler/erg_common/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub fn fmt_indent(s: String, depth: usize) -> String {
s.split('\n').map(|s| indent.clone() + s).collect()
}

/// 複数のオブジェクトからなるハッシュを得たい場合はタプルか配列で渡す
pub fn get_hash<T: std::hash::Hash>(t: &T) -> usize {
let mut s = fxhash::FxHasher::default();
t.hash(&mut s);
Expand Down
130 changes: 61 additions & 69 deletions compiler/erg_compiler/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use erg_common::{
use erg_type::codeobj::{CodeObj, CodeObjFlags};
use Opcode::*;

use erg_parser::ast::{Identifier, ParamPattern, Params, VarName, VarPattern};
use erg_parser::token::{Token, TokenCategory, TokenKind};
use erg_parser::ast::{Identifier, ParamPattern, Params, VarName};
use erg_parser::token::{Token, TokenKind};

use erg_type::value::ValueObj;
use erg_type::{HasType, TypeCode, TypePair};
Expand Down Expand Up @@ -680,50 +680,20 @@ impl CodeGenerator {
.collect()
}

fn emit_var_pat(&mut self, pat: VarPattern, op: &Token) {
match pat {
VarPattern::Ident(ident) => {
if op.category_is(TokenCategory::DefOp) {
self.emit_store_instr(ident, Name);
} else {
todo!()
}
}
VarPattern::Array(a) => {
if op.category_is(TokenCategory::DefOp) {
// TODO: UNPACK_EX
self.write_instr(UNPACK_SEQUENCE);
self.write_arg(a.len() as u8);
self.stack_inc_n(a.len() - 1);
for sig in a.into_iter() {
self.emit_var_pat(sig.pat, op);
}
} else {
switch_unreachable!()
}
}
_ => todo!(),
}
}

fn emit_mono_type_def(&mut self, sig: VarSignature, body: DefBody) {
self.write_instr(Opcode::LOAD_BUILD_CLASS);
self.write_arg(0);
self.stack_inc();
let ident = match sig.pat {
VarPattern::Ident(ident) => ident,
_ => todo!(),
};
let code = self.codegen_typedef_block(ident.inspect().clone(), body.block);
let code = self.codegen_typedef_block(sig.inspect().clone(), body.block);
self.emit_load_const(code);
self.emit_load_const(ident.inspect().clone());
self.emit_load_const(sig.inspect().clone());
self.write_instr(Opcode::MAKE_FUNCTION);
self.write_arg(0);
self.emit_load_const(ident.inspect().clone());
self.emit_load_const(sig.inspect().clone());
self.write_instr(Opcode::CALL_FUNCTION);
self.write_arg(2);
self.stack_dec_n((1 + 2) - 1);
self.emit_store_instr(ident, Name);
self.emit_store_instr(sig.ident, Name);
}

fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
Expand All @@ -735,7 +705,7 @@ impl CodeGenerator {
} else {
self.codegen_frameless_block(body.block, vec![]);
}
self.emit_var_pat(sig.pat, &body.op);
self.emit_store_instr(sig.ident, Name);
}

fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) {
Expand Down Expand Up @@ -1026,7 +996,7 @@ impl CodeGenerator {
}

fn codegen_expr(&mut self, expr: Expr) {
if expr.ln_begin().unwrap() > self.cur_block().prev_lineno {
if expr.ln_begin().unwrap_or_else(|| panic!("{expr}")) > self.cur_block().prev_lineno {
let sd = self.cur_block().lasti - self.cur_block().prev_lasti;
let ld = expr.ln_begin().unwrap() - self.cur_block().prev_lineno;
if ld != 0 {
Expand Down Expand Up @@ -1058,33 +1028,9 @@ impl CodeGenerator {
}
match expr {
Expr::Lit(lit) => {
self.emit_load_const(lit.data);
}
Expr::Accessor(Accessor::Local(local)) => {
self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name)))
.unwrap_or_else(|err| {
self.errs.push(err);
});
}
Expr::Accessor(Accessor::Public(public)) => {
let ident = Identifier::new(Some(public.dot), VarName::new(public.name));
self.emit_load_name_instr(ident).unwrap_or_else(|err| {
self.errs.push(err);
});
}
Expr::Accessor(Accessor::Attr(a)) => {
let class = a.obj.ref_t().name();
let uniq_obj_name = a.obj.__name__().map(Str::rc);
self.codegen_expr(*a.obj);
self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
a.name.content.clone(),
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
self.emit_load_const(lit.value);
}
Expr::Accessor(acc) => self.codegen_acc(acc),
Expr::Def(def) => match def.sig {
Signature::Subr(sig) => self.emit_subr_def(sig, def.body),
Signature::Var(sig) => self.emit_var_def(sig, def.body),
Expand Down Expand Up @@ -1255,9 +1201,7 @@ impl CodeGenerator {
// record name, let it be anonymous
self.emit_load_const("Record");
for field in rec.attrs.iter() {
self.emit_load_const(ValueObj::Str(
field.sig.ident().unwrap().inspect().clone(),
));
self.emit_load_const(ValueObj::Str(field.sig.ident().inspect().clone()));
}
self.write_instr(BUILD_LIST);
self.write_arg(attrs_len as u8);
Expand Down Expand Up @@ -1295,6 +1239,50 @@ impl CodeGenerator {
}
}

fn codegen_acc(&mut self, acc: Accessor) {
match acc {
Accessor::Local(local) => {
self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name)))
.unwrap_or_else(|err| {
self.errs.push(err);
});
}
Accessor::Public(public) => {
let ident = Identifier::new(Some(public.dot), VarName::new(public.name));
self.emit_load_name_instr(ident).unwrap_or_else(|err| {
self.errs.push(err);
});
}
Accessor::Attr(a) => {
let class = a.obj.ref_t().name();
let uniq_obj_name = a.obj.__name__().map(Str::rc);
self.codegen_expr(*a.obj);
self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
a.name.content.clone(),
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
}
Accessor::TupleAttr(t_attr) => {
self.codegen_expr(*t_attr.obj);
self.emit_load_const(t_attr.index.value);
self.write_instr(BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
}
Accessor::Subscr(subscr) => {
self.codegen_expr(*subscr.obj);
self.codegen_expr(*subscr.index);
self.write_instr(BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
}
}
}

/// forブロックなどで使う
fn codegen_frameless_block(&mut self, block: Block, params: Vec<Str>) {
for param in params {
Expand Down Expand Up @@ -1440,6 +1428,9 @@ impl CodeGenerator {
print_point = self.cur_block().lasti;
self.emit_load_name_instr(Identifier::public("print"))
.unwrap();
// Consistency will be taken later (when NOP replacing)
// 後で(NOP書き換え時)整合性を取る
self.stack_dec();
}
for expr in hir.module.into_iter() {
self.codegen_expr(expr);
Expand All @@ -1450,14 +1441,15 @@ impl CodeGenerator {
}
self.cancel_pop_top(); // 最後の値は戻り値として取っておく
if self.input().is_repl() {
if self.cur_block().stack_len == 1 {
if self.cur_block().stack_len == 0 {
// remains `print`, nothing to be printed
self.edit_code(print_point, Opcode::NOP as usize);
} else {
self.stack_inc();
self.write_instr(CALL_FUNCTION);
self.write_arg(1_u8);
}
self.stack_dec();
self.stack_dec_n(self.cur_block().stack_len as usize);
}
if self.cur_block().stack_len == 0 {
self.emit_load_const(ValueObj::None);
Expand Down
56 changes: 16 additions & 40 deletions compiler/erg_compiler/context/inquire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use erg_common::dict::Dict;
use erg_common::error::ErrorCore;
use erg_common::levenshtein::levenshtein;
use erg_common::set::Set;
use erg_common::traits::{Locational, Stream};
use erg_common::traits::Locational;
use erg_common::vis::{Field, Visibility};
use erg_common::Str;
use erg_common::{enum_unwrap, fmt_option, fmt_slice, log, set};
Expand Down Expand Up @@ -36,48 +36,24 @@ use Visibility::*;
impl Context {
pub(crate) fn validate_var_sig_t(
&self,
sig: &ast::VarSignature,
ident: &ast::Identifier,
t_spec: Option<&ast::TypeSpec>,
body_t: &Type,
mode: RegistrationMode,
) -> TyCheckResult<()> {
let spec_t = self.instantiate_var_sig_t(sig, None, mode)?;
match &sig.pat {
ast::VarPattern::Discard(token) => {
if self
.sub_unify(body_t, &spec_t, None, Some(sig.loc()))
.is_err()
{
return Err(TyCheckError::type_mismatch_error(
line!() as usize,
token.loc(),
self.caused_by(),
"_",
&spec_t,
body_t,
));
}
}
ast::VarPattern::Ident(ident) => {
if self
.sub_unify(body_t, &spec_t, None, Some(sig.loc()))
.is_err()
{
return Err(TyCheckError::type_mismatch_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
&spec_t,
body_t,
));
}
}
ast::VarPattern::Array(a) => {
for (elem, inf_elem_t) in a.iter().zip(body_t.inner_ts().iter()) {
self.validate_var_sig_t(elem, inf_elem_t, mode)?;
}
}
_ => todo!(),
let spec_t = self.instantiate_var_sig_t(t_spec, None, mode)?;
if self
.sub_unify(body_t, &spec_t, None, Some(ident.loc()))
.is_err()
{
return Err(TyCheckError::type_mismatch_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
&spec_t,
body_t,
));
}
Ok(())
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/erg_compiler/context/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,17 +370,17 @@ impl ConstTemplate {
impl Context {
pub(crate) fn instantiate_var_sig_t(
&self,
sig: &ast::VarSignature,
t_spec: Option<&TypeSpec>,
opt_eval_t: Option<Type>,
mode: RegistrationMode,
) -> TyCheckResult<Type> {
let spec_t = if let Some(s) = sig.t_spec.as_ref() {
let spec_t = if let Some(s) = t_spec {
self.instantiate_typespec(s, mode)?
} else {
free_var(self.level, Constraint::type_of(Type))
};
if let Some(eval_t) = opt_eval_t {
self.sub_unify(&eval_t, &spec_t, None, sig.t_spec.as_ref().map(|s| s.loc()))?;
self.sub_unify(&eval_t, &spec_t, None, t_spec.map(|s| s.loc()))?;
}
Ok(spec_t)
}
Expand Down
Loading

0 comments on commit b36b400

Please sign in to comment.