Skip to content

Commit ff59766

Browse files
authored
Merge pull request #198 from JSAbrahams/v0.3.0
V0.3.0
2 parents 3065bcd + 15456b9 commit ff59766

File tree

249 files changed

+7231
-6300
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

249 files changed

+7231
-6300
lines changed

Cargo.lock

Lines changed: 168 additions & 157 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "mamba"
3-
version = "0.2.2"
4-
authors = ["Joel Abrahams <abrahamsjo@gmail.com>"]
5-
description = "A transpiler which translates Mamba to Python 3 files"
3+
version = "0.3.0"
4+
authors = ["Joël Abrahams <abrahamsjo@gmail.com>"]
5+
description = "A transpiler which converts Mamba files to Python 3 files"
66
edition = "2018"
77
license-file = "LICENSE"
88

@@ -17,10 +17,13 @@ appveyor = { repository = "JSAbrahams/mamba", branch = "master", service = "gith
1717
travis-ci = { repository = "JSAbrahams/mamba", branch = "master" }
1818

1919
[dependencies]
20+
tempfile = "3.1.0"
2021
assert_cmd = "0.10"
2122
python-parser = "0.1.0"
2223
clap = {version = "2.33", features = ["yaml"]}
23-
leg = "0.1.3"
2424
pathdiff = "0.1.0"
2525
glob = "0.3.0"
2626
itertools = "0.8.2"
27+
log = "0.4"
28+
loggerv = "0.7"
29+
ansi_term = "0.12.1"

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ For more extensive examples and explanations check out the [documentation](https
4444

4545
We can write a simple script that computes the factorial of a value given by the user.
4646
```mamba
47-
def factorial(x: Int) => match x
47+
def factorial(x: Int) -> Int => match x
4848
0 => 1
4949
n => n * factorial(n - 1)
5050
@@ -321,7 +321,21 @@ In future we might want to add an option to compile down to Python bytecode, but
321321

322322
### Usage
323323
```
324-
mamba [OPTIONS]
324+
mamba [FLAGS] [OPTIONS]
325+
```
326+
327+
### FLAGS
328+
```
329+
-d, --debug Add line numbers to log statements
330+
-h, --help Prints help information
331+
-l, --level Print log level
332+
--no-module-path Disable the module path in the log statements
333+
--no-color Disable colorized output
334+
-v Set level of verbosity
335+
- : info, error, warning printed to sterr (Default)
336+
- v : debug messages are printed
337+
- vv : trace messages are printed
338+
-V, --version Prints version information
325339
```
326340

327341
### Options
@@ -330,7 +344,7 @@ mamba [OPTIONS]
330344
If file, file taken as input.
331345
If directory, recursively search all sub-directories for *.mamba files.
332346
If no input given, current directory used as input directory.
333-
-o, --output <OUTPUT> Output directory to store mamba files.
347+
-o, --output <OUTPUT> Output directory to store Python files.
334348
Output directory structure reflects input directory structure.
335349
If no output given, 'target' directory created in current directory and is used as ouput.
336350
```
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use crate::check::constrain::constraint::expected::Expected;
2+
use crate::check::constrain::constraint::iterator::Constraints;
3+
use crate::check::constrain::constraint::Constraint;
4+
use crate::check::context::name::DirectName;
5+
use crate::check::result::{TypeErr, TypeResult};
6+
use crate::common::position::Position;
7+
8+
/// Constraint Builder.
9+
///
10+
/// Allows us to build sets of constraints.
11+
/// This allows us to constrain different parts of the program which may rely on
12+
/// the same logic, without interfering with each other. E.g. different
13+
/// functions within the same class.
14+
///
15+
/// The level indicates how deep we are. A level of 0 indicates that we are at
16+
/// the top-level of a script.
17+
#[derive(Clone, Debug)]
18+
pub struct ConstrBuilder {
19+
pub level: usize,
20+
finished: Vec<(Vec<DirectName>, Vec<Constraint>)>,
21+
constraints: Vec<(Vec<DirectName>, Vec<Constraint>)>
22+
}
23+
24+
impl ConstrBuilder {
25+
pub fn new() -> ConstrBuilder {
26+
ConstrBuilder { level: 0, finished: vec![], constraints: vec![(vec![], vec![])] }
27+
}
28+
29+
pub fn is_top_level(&self) -> bool { self.level == 0 }
30+
31+
pub fn new_set_in_class(&mut self, inherit_class: bool, class: &DirectName) {
32+
self.new_set(false);
33+
if self.level > 0 && inherit_class {
34+
let mut previous = self.constraints[self.level - 1].0.clone();
35+
self.constraints[self.level].0.append(&mut previous);
36+
}
37+
self.constraints[self.level].0.push(class.clone());
38+
}
39+
40+
/// Remove all constraints with where either parent or child is expected
41+
pub fn remove_expected(&mut self, expected: &Expected) {
42+
self.constraints[self.level].1 = self.constraints[self.level]
43+
.1
44+
.clone()
45+
.drain_filter(|con| {
46+
!con.parent.expect.structurally_eq(&expected.expect)
47+
&& !con.child.expect.structurally_eq(&expected.expect)
48+
})
49+
.collect()
50+
}
51+
52+
pub fn new_set(&mut self, inherit: bool) {
53+
self.constraints.push(if inherit {
54+
(self.constraints[self.level].0.clone(), self.constraints[self.level].1.clone())
55+
} else {
56+
(vec![], vec![])
57+
});
58+
self.level += 1;
59+
}
60+
61+
pub fn exit_set(&mut self, pos: &Position) -> TypeResult<()> {
62+
if self.level == 0 {
63+
return Err(vec![TypeErr::new(pos, "Cannot exit top-level set")]);
64+
}
65+
66+
self.finished.push(self.constraints.remove(self.level));
67+
self.level -= 1;
68+
Ok(())
69+
}
70+
71+
pub fn add_with_identifier(
72+
&mut self,
73+
msg: &str,
74+
parent: &Expected,
75+
child: &Expected,
76+
idens: &[String]
77+
) {
78+
let mut constr = Constraint::new(msg, parent, child);
79+
constr.ids.append(&mut Vec::from(idens));
80+
self.add_constr(&constr);
81+
}
82+
83+
pub fn add(&mut self, msg: &str, parent: &Expected, child: &Expected) {
84+
self.add_constr(&Constraint::new(msg, parent, child));
85+
}
86+
87+
pub fn add_constr(&mut self, constraint: &Constraint) {
88+
self.constraints[self.level].1.push(constraint.clone())
89+
}
90+
91+
// It is not redundant
92+
#[allow(clippy::redundant_clone)]
93+
pub fn all_constr(self) -> Vec<Constraints> {
94+
let mut finished = self.finished.clone();
95+
finished.append(&mut self.constraints.clone());
96+
finished.iter().map(Constraints::from).collect()
97+
}
98+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use std::convert::TryFrom;
2+
use std::fmt;
3+
use std::fmt::{Display, Error, Formatter};
4+
use std::hash::Hash;
5+
use std::ops::Deref;
6+
7+
use itertools::{EitherOrBoth, Itertools};
8+
9+
use crate::check::constrain::constraint::expected::Expect::*;
10+
use crate::check::context::clss;
11+
use crate::check::context::clss::{BOOL_PRIMITIVE, FLOAT_PRIMITIVE, INT_PRIMITIVE, STRING_PRIMITIVE};
12+
use crate::check::context::name::{DirectName, NameUnion};
13+
use crate::check::result::{TypeErr, TypeResult};
14+
use crate::common::delimit::comma_delm;
15+
use crate::common::position::Position;
16+
use crate::parse::ast::{Node, AST};
17+
18+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
19+
pub struct Expected {
20+
pub pos: Position,
21+
pub expect: Expect
22+
}
23+
24+
impl Expected {
25+
pub fn new(pos: &Position, expect: &Expect) -> Expected {
26+
Expected { pos: pos.clone(), expect: expect.clone() }
27+
}
28+
}
29+
30+
impl TryFrom<&AST> for Expected {
31+
type Error = Vec<TypeErr>;
32+
33+
/// Creates Expected from AST.
34+
///
35+
/// If primitive or Constructor, constructs Type.
36+
fn try_from(ast: &AST) -> TypeResult<Expected> {
37+
let ast = match &ast.node {
38+
Node::Block { statements } | Node::Script { statements } =>
39+
statements.last().unwrap_or(ast),
40+
_ => ast
41+
};
42+
43+
let expect = match &ast.node {
44+
Node::Int { .. } | Node::ENum { .. } => Type { name: NameUnion::from(INT_PRIMITIVE) },
45+
Node::Real { .. } => Type { name: NameUnion::from(FLOAT_PRIMITIVE) },
46+
Node::Bool { .. } => Type { name: NameUnion::from(BOOL_PRIMITIVE) },
47+
Node::Str { .. } => Type { name: NameUnion::from(STRING_PRIMITIVE) },
48+
Node::Undefined => Nullable,
49+
Node::Underscore => ExpressionAny,
50+
_ => Expression { ast: ast.clone() }
51+
};
52+
53+
Ok(Expected::new(&ast.pos, &expect))
54+
}
55+
}
56+
57+
impl TryFrom<&Box<AST>> for Expected {
58+
type Error = Vec<TypeErr>;
59+
60+
fn try_from(ast: &Box<AST>) -> TypeResult<Expected> { Expected::try_from(ast.deref()) }
61+
}
62+
63+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
64+
pub enum Expect {
65+
Nullable,
66+
Expression { ast: AST },
67+
ExpressionAny,
68+
Collection { ty: Box<Expected> },
69+
Raises { name: NameUnion },
70+
Function { name: DirectName, args: Vec<Expected> },
71+
Field { name: String },
72+
Access { entity: Box<Expected>, name: Box<Expected> },
73+
Type { name: NameUnion }
74+
}
75+
76+
impl Display for Expected {
77+
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { write!(f, "{}", self.expect) }
78+
}
79+
80+
impl Expected {
81+
pub fn is_expr(&self) -> bool {
82+
if let Expression { .. } = self.expect {
83+
true
84+
} else {
85+
false
86+
}
87+
}
88+
}
89+
90+
impl Display for Expect {
91+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
92+
write!(f, "{}", match &self {
93+
Nullable => String::from("None"),
94+
ExpressionAny => String::from("Any"),
95+
Expression { ast } => format!("{}", ast.node),
96+
Collection { ty } => format!("Collection[{}]", ty.expect),
97+
Raises { name: ty } => format!("Raises[{}]", ty),
98+
Access { entity, name } => format!("{}.{}", entity.expect, name.expect),
99+
Function { name, args } => format!("{}({})", name, comma_delm(args)),
100+
Field { name } => name.clone(),
101+
Type { name: ty } => format!("{}", ty)
102+
})
103+
}
104+
}
105+
106+
impl Expect {
107+
pub fn structurally_eq(&self, other: &Self) -> bool {
108+
match (self, other) {
109+
(Collection { ty: l }, Collection { ty: r }) => l.expect.structurally_eq(&r.expect),
110+
(Field { name: l }, Field { name: r }) => l == r,
111+
(Raises { name: l }, Raises { name: r }) | (Type { name: l }, Type { name: r }) =>
112+
l == r,
113+
(Access { entity: le, name: ln }, Access { entity: re, name: rn }) =>
114+
le == re && ln == rn,
115+
(Function { name: l, args: la }, Function { name: r, args: ra }) =>
116+
l == r
117+
&& la.iter().zip_longest(ra.iter()).all(|pair| {
118+
if let EitherOrBoth::Both(left, right) = pair {
119+
left.expect.structurally_eq(&right.expect)
120+
} else {
121+
false
122+
}
123+
}),
124+
125+
(Expression { ast: l }, Expression { ast: r }) => l.equal_structure(r),
126+
127+
(ExpressionAny, ExpressionAny) | (Nullable, Nullable) => true,
128+
129+
(Type { name: ty, .. }, Expression { ast: AST { node: Node::Str { .. }, .. } })
130+
| (Expression { ast: AST { node: Node::Str { .. }, .. } }, Type { name: ty, .. })
131+
if ty == &NameUnion::from(clss::STRING_PRIMITIVE) =>
132+
true,
133+
(Type { name: ty, .. }, Expression { ast: AST { node: Node::Real { .. }, .. } })
134+
| (Expression { ast: AST { node: Node::Real { .. }, .. } }, Type { name: ty, .. })
135+
if ty == &NameUnion::from(clss::FLOAT_PRIMITIVE) =>
136+
true,
137+
(Type { name: ty, .. }, Expression { ast: AST { node: Node::Int { .. }, .. } })
138+
| (Expression { ast: AST { node: Node::Int { .. }, .. } }, Type { name: ty, .. })
139+
if ty == &NameUnion::from(clss::INT_PRIMITIVE) =>
140+
true,
141+
142+
_ => false
143+
}
144+
}
145+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use std::collections::VecDeque;
2+
3+
use crate::check::constrain::constraint::expected::Expected;
4+
use crate::check::constrain::constraint::Constraint;
5+
use crate::check::context::name::DirectName;
6+
use crate::check::result::{TypeErr, TypeResult};
7+
8+
#[derive(Clone, Debug)]
9+
pub struct Constraints {
10+
pub in_class: Vec<DirectName>,
11+
constraints: VecDeque<Constraint>
12+
}
13+
14+
impl From<&(Vec<DirectName>, Vec<Constraint>)> for Constraints {
15+
fn from((in_class, constraints): &(Vec<DirectName>, Vec<Constraint>)) -> Self {
16+
let constraints = VecDeque::from(constraints.clone());
17+
Constraints { in_class: in_class.clone(), constraints }
18+
}
19+
}
20+
21+
impl Constraints {
22+
pub fn new(in_class: &[DirectName]) -> Constraints {
23+
Constraints { in_class: Vec::from(in_class), constraints: VecDeque::new() }
24+
}
25+
26+
pub fn len(&self) -> usize { self.constraints.len() }
27+
28+
pub fn pop_constr(&mut self) -> Option<Constraint> { self.constraints.pop_front() }
29+
30+
/// Push constraint at front so that it will be analysed next.
31+
///
32+
/// Only used during unification stage.
33+
/// Marks constraint as generated.
34+
pub fn push(&mut self, msg: &str, parent: &Expected, child: &Expected) {
35+
self.constraints.push_front(Constraint::new(msg, parent, child).as_gen())
36+
}
37+
38+
/// Append in_class and constraints of constraints to self
39+
pub fn append(&mut self, constraints: &mut Constraints) {
40+
self.in_class.append(&mut constraints.in_class);
41+
self.constraints.append(&mut constraints.constraints)
42+
}
43+
44+
pub fn push_constr(&mut self, constr: &Constraint) {
45+
self.constraints.push_back(constr.clone())
46+
}
47+
48+
pub fn reinsert(&mut self, constraint: &Constraint) -> TypeResult<()> {
49+
if constraint.is_flag {
50+
// Can only reinsert constraint once
51+
let msg = format!(
52+
"Cannot infer type, expected '{}' but was '{}'",
53+
&constraint.parent.expect, &constraint.child.expect
54+
);
55+
return Err(vec![TypeErr::new(&constraint.parent.pos, &msg)]);
56+
}
57+
58+
self.constraints.push_back(constraint.flag());
59+
Ok(())
60+
}
61+
}
62+
63+
impl Default for Constraints {
64+
fn default() -> Self { Constraints::new(&[]) }
65+
}

0 commit comments

Comments
 (0)