Skip to content

Commit

Permalink
feat: add std library
Browse files Browse the repository at this point in the history
  • Loading branch information
Ph0enixKM committed Sep 28, 2022
1 parent 85c662a commit 669c99e
Show file tree
Hide file tree
Showing 17 changed files with 115 additions and 54 deletions.
30 changes: 15 additions & 15 deletions setup/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,27 @@ arch=$(if [ $([ "_$(uname -m)" != "_arm64" ]; echo $?) != 0 ]; then echo "aarch6
url="https://github.com/Ph0enixKM/${name}/releases/download/${tag}/amber_${os}_${arch}";
test -d "${place}" > /dev/null;
if [ $([ "_$(echo $?)" != "_0" ]; echo $?) != 0 ]; then
echo "Amber already installed" ;
echo "It seems that Amber is already installed on your system.";
echo "If you want to reinstall Amber - try to uninstall it first.";
echo "(Find out more at https://amber.marbl.cc)";
exit 0
echo "Amber already installed" ;
echo "It seems that Amber is already installed on your system.";
echo "If you want to reinstall Amber - try to uninstall it first.";
echo "(Find out more at https://amber.marbl.cc)";
exit 0
fi;
echo "Installing Amber" ;
if [ $([ "_$(ruby -v > /dev/null; echo $?)" != "_0" ]; echo $?) != 0 ]; then
code="require \"open-uri\"; open(\"${target}\", \"wb\") do |file|; file << open(\"${url}\").read; end";
echo "Using ruby as a download method...";
ruby -e "${code}"
code="require \"open-uri\"; open(\"${target}\", \"wb\") do |file|; file << open(\"${url}\").read; end";
echo "Using ruby as a download method...";
ruby -e "${code}"
elif [ $([ "_$(curl -v > /dev/null; echo $?)" != "_0" ]; echo $?) != 0 ]; then
echo "Using curl as a download method...";
curl -o "${target}" "${url}"
echo "Using curl as a download method...";
curl -o "${target}" "${url}"
elif [ $([ "_$(wget -v > /dev/null; echo $?)" != "_0" ]; echo $?) != 0 ]; then
echo "Using wget as a download method...";
wget -O "${target}" "${url}"
echo "Using wget as a download method...";
wget -O "${target}" "${url}"
else
echo "Neither ruby, curl or wget are installed on your system.";
echo "Please install one of them and try again.";
exit 1
echo "Neither ruby, curl or wget are installed on your system.";
echo "Please install one of them and try again.";
exit 1
fi;
sudo mkdir ${place} > /dev/null;
sudo mv ${target} ${place}/${target};
Expand Down
8 changes: 4 additions & 4 deletions setup/uninstall.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
place="/opt/amber";
test -d "${place}" > /dev/null;
if [ $([ "_$(echo $?)" != "_0" ]; echo $?) != 0 ]; then
sudo rm -rf "${place}";
sudo rm '/usr/local/bin/amber';
echo 'Uninstalled Amber successfully 🎉'
sudo rm -rf "${place}";
sudo rm '/usr/local/bin/amber';
echo 'Uninstalled Amber successfully 🎉'
else
echo 'Amber is not installed'
echo 'Amber is not installed'
fi
26 changes: 13 additions & 13 deletions src/cli/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fn hello_world() {

#[test]
fn hello_world_error() {
test_amber_err!("echo Hello World", "Variable 'echo' does not exist");
test_amber_err!("echo Hello World", "Variable 'Hello' does not exist");
}

#[test]
Expand Down Expand Up @@ -388,7 +388,7 @@ fn function() {
fun test() {
$echo Hello World$
}
test()
echo test()
";
test_amber!(code, "Hello World");
}
Expand All @@ -400,9 +400,9 @@ fn function_with_args() {
$echo {a}$
$echo {b}$
}
test('Hello', 'World')
echo test('Hello', 'World')
";
test_amber!(code, "Hello\nWorld");
test_amber!(code, "Hello World");
}

#[test]
Expand All @@ -411,8 +411,8 @@ fn function_with_args_different_types() {
fun test(a, b) {
$echo {a + b}$
}
test('Hello', 'World')
test(11, 42)
echo test('Hello', 'World')
echo test(11, 42)
";
test_amber!(code, "HelloWorld\n53");
}
Expand All @@ -423,7 +423,7 @@ fn function_with_typed_args() {
fun test(a: Num, b: Num) {
$echo {a + b}$
}
test(11, 42)
echo test(11, 42)
";
test_amber!(code, "53");
}
Expand All @@ -434,9 +434,9 @@ fn function_with_typed_different_args() {
$echo {a}$
$echo {b}$
}
test(11, 'Hello')
echo test(11, 'Hello')
";
test_amber!(code, "11\nHello");
test_amber!(code, "11 Hello");
}

#[test]
Expand All @@ -445,16 +445,16 @@ fn function_with_typed_args_text() {
fun test(a: Text, b: Text) {
$echo {a + b}$
}
test('Hello', 'World')
echo test('Hello', 'World')
";
test_amber!(code, "HelloWorld");
}

#[test]
fn import_existing_file() {
let code = "
import * from 'tests/io/print.ab'
print('Hello World')
import * from 'tests/str/trim.ab'
echo trim(' Hello World ')
";
test_amber!(code, "Hello World");
}
Expand All @@ -463,7 +463,7 @@ fn import_existing_file() {
fn import_existing_nested_file() {
let code = "
import * from 'tests/is_even.ab'
is_even(10)
echo is_even(10)
";
test_amber!(code, "even");
}
16 changes: 11 additions & 5 deletions src/compiler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use heraclitus_compiler::prelude::*;
use crate::modules::block;
use crate::modules::block::Block;
use crate::translate::check_all_blocks;
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::module::TranslateModule;
Expand Down Expand Up @@ -48,13 +48,13 @@ impl AmberCompiler {
}
}

pub fn parse(&self, tokens: Vec<Token>) -> Result<(block::Block, ParserMetadata), Message> {
pub fn parse(&self, tokens: Vec<Token>) -> Result<(Block, ParserMetadata), Message> {
let code = self.cc.code.as_ref().expect(NO_CODE_PROVIDED).clone();
let mut meta = ParserMetadata::new(tokens, self.path.clone(), Some(code));
if let Err(Failure::Loud(err)) = check_all_blocks(&mut meta) {
return Err(err);
}
let mut block = block::Block::new();
let mut block = Block::new();
// Parse with debug or not
let result = if let Ok(value) = env::var("AMBER_DEBUG_PARSER") {
if value == "true" {
Expand All @@ -72,7 +72,7 @@ impl AmberCompiler {
}
}

pub fn translate(&self, block: block::Block, meta: ParserMetadata) -> String {
pub fn translate(&self, block: Block, meta: ParserMetadata) -> String {
let mut meta = TranslateMetadata::new(&meta);
block.translate(&mut meta)
}
Expand All @@ -89,12 +89,18 @@ impl AmberCompiler {
}

#[allow(dead_code)]
pub fn test_eval(&self) -> Result<String, Message> {
pub fn test_eval(&mut self) -> Result<String, Message> {
self.compile().map_or_else(Err, |(code, _)| {
let child = Command::new("/bin/bash")
.arg("-c").arg::<&str>(code.as_ref())
.output().unwrap();
Ok(String::from_utf8_lossy(&child.stdout).to_string())
})
}

pub fn import_std() -> String {
[
include_str!("std/main.ab")
].join("\n")
}
}
32 changes: 32 additions & 0 deletions src/modules/builtin/echo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use heraclitus_compiler::prelude::*;
use crate::modules::expression::expr::Expr;
use crate::translate::module::TranslateModule;
use crate::utils::{ParserMetadata, TranslateMetadata};

#[derive(Debug, Clone)]
pub struct Echo {
value: Box<Expr>
}

impl SyntaxModule<ParserMetadata> for Echo {
syntax_name!("Log");

fn new() -> Self {
Echo {
value: Box::new(Expr::new())
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
token(meta, "echo")?;
syntax(meta, &mut *self.value)?;
Ok(())
}
}

impl TranslateModule for Echo {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let value = self.value.translate(meta);
format!("echo {}", value)
}
}
1 change: 1 addition & 0 deletions src/modules/builtin/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod echo;
2 changes: 1 addition & 1 deletion src/modules/function/invocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,6 @@ impl TranslateModule for FunctionInvocation {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let name = if self.variant_id != 0 { format!("__{}_{}", self.variant_id, self.name) } else { self.name.clone() };
let args = self.args.iter().map(|arg| arg.translate(meta)).collect::<Vec<String>>().join(" ");
format!("{name} {args}")
format!("$({name} {args})")
}
}
8 changes: 6 additions & 2 deletions src/modules/imports/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl Import {
}

fn handle_import(&mut self, meta: &mut ParserMetadata, tok: Option<Token>, imported_code: String) -> SyntaxResult {
match AmberCompiler::new(imported_code.clone(), meta.path.clone()).tokenize() {
match AmberCompiler::new(imported_code.clone(), Some(self.path.value.clone())).tokenize() {
Ok(tokens) => {
// Save snapshot of current file
let code = meta.code.clone();
Expand Down Expand Up @@ -114,7 +114,11 @@ impl SyntaxModule<ParserMetadata> for Import {
token(meta, "from")?;
let tok_str = meta.get_current_token();
syntax(meta, &mut self.path)?;
let imported_code = self.resolve_import(meta, tok_str)?;
let imported_code = if self.path.value == "[standard library]" {
AmberCompiler::import_std()
} else {
self.resolve_import(meta, tok_str)?
};
self.handle_import(meta, tok, imported_code)?;
Ok(())
}
Expand Down
9 changes: 9 additions & 0 deletions src/modules/imports/import_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ pub struct ImportString {
pub value: String
}

impl ImportString {
pub fn std_lib_path(&mut self) {
if self.value == "std" {
self.value = "[standard library]".to_string();
}
}
}

impl SyntaxModule<ParserMetadata> for ImportString {
syntax_name!("Import String");

Expand All @@ -19,6 +27,7 @@ impl SyntaxModule<ParserMetadata> for ImportString {
let value = token_by(meta, |word| word.starts_with('\''))?;
if value.ends_with('\'') {
self.value = value[1..value.len() - 1].to_string();
self.std_lib_path();
}
else {
return error!(meta, meta.get_current_token(), "Import string cannot interpolate expressions")
Expand Down
1 change: 0 additions & 1 deletion src/modules/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ impl SyntaxModule<ParserMetadata> for Main {
token(meta, "main")?;
// Main cannot be parsed inside of a block
if meta.mem.get_depth() > 1 {
dbg!(meta.mem.get_depth());
return error!(meta, tok, "Main module must be in the global scope")
}
// If this main is included in other file, skip it
Expand Down
1 change: 1 addition & 0 deletions src/modules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod function;
pub mod types;
pub mod imports;
pub mod main;
pub mod builtin;

#[macro_export]
macro_rules! handle_types {
Expand Down
10 changes: 6 additions & 4 deletions src/modules/statement/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::modules::imports::{
import::Import
};
use crate::modules::main::Main;
use crate::modules::builtin::echo::Echo;

#[derive(Debug, Clone)]
pub enum StatementType {
Expand All @@ -50,7 +51,8 @@ pub enum StatementType {
Continue(Continue),
FunctionDeclaration(FunctionDeclaration),
Import(Import),
Main(Main)
Main(Main),
Echo(Echo)
}

#[derive(Debug, Clone)]
Expand All @@ -75,7 +77,7 @@ impl Statement {
ShorthandMul, ShorthandDiv,
ShorthandModulo,
// Command
CommandStatement,
CommandStatement, Echo,
// Expression
Expr
]);
Expand Down Expand Up @@ -128,8 +130,8 @@ impl TranslateModule for Statement {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let translated = self.translate_match(meta, self.value.as_ref().unwrap());
// This is a workaround that handles $(...) which cannot be used as a statement
if translated.starts_with("$(") {
if translated.starts_with('$') {
format!("echo {} > /dev/null 2>&1", translated)
} else { translated }
}
}
}
3 changes: 3 additions & 0 deletions src/modules/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ impl Display for Type {

pub trait Typed {
fn get_type(&self) -> Type;
fn has_echo(&self) -> bool {
false
}
}

pub fn parse_type(meta: &mut ParserMetadata) -> Result<Type, Failure> {
Expand Down
4 changes: 4 additions & 0 deletions src/std/main.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub fun input() {
$read$
echo '$REPLY'
}
7 changes: 0 additions & 7 deletions tests/io/print.ab

This file was deleted.

4 changes: 2 additions & 2 deletions tests/is_even.ab
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * from 'io/print.ab';
import * from 'str/trim.ab';

pub fun is_even(n: Num) {
print(n % 2 == 0 then 'even' else 'odd')
echo n % 2 == 0 then trim(' even ') else 'odd'
}
7 changes: 7 additions & 0 deletions tests/str/trim.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub fun trim(text) {
echo '$\{text##*( )}'
}

main {
trim('long text')
}

0 comments on commit 669c99e

Please sign in to comment.