Skip to content

Commit

Permalink
[orgams] Start to work on expression conversion and tests for orgams …
Browse files Browse the repository at this point in the history
…output
  • Loading branch information
Krusty/Benediction committed Aug 27, 2024
1 parent 0fd7b0d commit 66a54f8
Show file tree
Hide file tree
Showing 9 changed files with 296 additions and 40 deletions.
226 changes: 203 additions & 23 deletions cpclib-asm/src/orgams.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use std::ops::Deref;
use beef::lean::Cow;
use cpclib_common::camino::Utf8Path;
use cpclib_common::itertools::Itertools;
use cpclib_tokens::{ListingElement, MacroParamElement, Token};
use cpclib_tokens::{BinaryOperation, DataAccess, DataAccessElem, Expr, ExprElement, ListingElement, MacroParamElement, Mnemonic, TestKind, TestKindElement, Token};

use crate::{parse_z80, r#macro, MayHaveSpan, SourceString, TokenExt};
use crate::{parse_z80, LocatedDataAccess, LocatedExpr, LocatedTestKind, MayHaveSpan, SourceString, TokenExt};

#[derive(Debug)]
pub struct ToOrgamsError(String);
Expand All @@ -16,15 +16,15 @@ impl Display for ToOrgamsError {
f.write_str(&self.0)
}
}
impl Into<ToOrgamsError> for &str {
impl Into<ToOrgamsError> for String {
fn into(self) -> ToOrgamsError {
ToOrgamsError(self.into())
ToOrgamsError(self)
}
}
impl Into<ToOrgamsError> for &std::io::Error {
fn into(self) -> ToOrgamsError {
let content = self.to_string();
content.as_str().into()
content.into()
}
}

Expand All @@ -33,20 +33,144 @@ pub trait ToOrgams {
fn to_orgams_string(&self) -> Result<Cow<str>, ToOrgamsError>;
}

// impl ToOrgams for Token {
// fn to_orgams_string(&self) -> Result<Cow<str>, ToOrgamsError> {
// todo!()
// }
// }

impl<T: TokenExt + MayHaveSpan + ListingElement + Display> ToOrgams for T {
impl ToOrgams for Mnemonic {
fn to_orgams_string(&self) -> Result<Cow<str>, ToOrgamsError> {
Ok(self.to_string().to_lowercase().into())
}
}

impl ToOrgams for BinaryOperation {
fn to_orgams_string(&self) -> Result<Cow<str>, ToOrgamsError> {
Ok(self.to_string().to_uppercase().into())
}
}

macro_rules! expr_to_orgams {
() => {
fn to_orgams_string(&self) -> Result<Cow<str>, ToOrgamsError> {
let repr = match self {

Self::Value(v,..) => {
if self.has_span() {
// basm allow _ between numbers
let span = dbg!(self.span().as_str().replace("_", ""));
if span.starts_with("0x") || span.starts_with("0X") {
format!("&{}", &span[2..])
} else if span.starts_with("#") {
format!("&{}", &span[1..])
} else {
format!("{}", v)
}
} else {
format!("&{:x}", v)
}
},

Self::Label(l) => {
format!("{}", l)
}

Self::BinaryOperation(op, left, right, ..) => {
let rleft = left.to_orgams_string()?;
let rright = right.to_orgams_string()?;
let rleft = rleft.as_ref();
let op = op.to_orgams_string()?;

let protect = |expr: &Self, repr: &str| -> String {
if expr.is_label() || expr.is_value() {
repr.into()
} else {
format!("[{}]", repr).into()
}
};

let rleft = protect(left, rleft.as_ref());
let rright = protect(right, rright.as_ref());

format!("{}{}{}", rleft, op, rright)
}

_ => unimplemented!("{:?}", self)
};

Ok(repr.into())
}
}
}

impl ToOrgams for LocatedExpr {
expr_to_orgams!();
}

impl ToOrgams for Expr {
expr_to_orgams!();
}

macro_rules! test_kind_to_orgams {
() => {
fn to_orgams_string(&self) -> Result<Cow<str>, ToOrgamsError> {
if self.is_true_test() {
let expr = self.expr_unchecked();
Ok(format!("IF {}", expr.to_orgams_string()?).into())
} else {
Err(format!("{:?}", self).into())
}
}
};
}

impl ToOrgams for LocatedTestKind {
test_kind_to_orgams!();
}

impl ToOrgams for TestKind {
test_kind_to_orgams!();
}


macro_rules! data_access_to_orgams {
() => {
fn to_orgams_string(&self) -> Result<Cow<str>, ToOrgamsError> {

let repr = if self.is_expression() {
let exp = self.get_expression().unwrap();
return exp.to_orgams_string();
}
else {
self.to_string().to_lowercase()
};

Ok(repr.into())
}

};
}



impl ToOrgams for DataAccess {
data_access_to_orgams!();
}

impl ToOrgams for LocatedDataAccess {
data_access_to_orgams!();
}

impl<T> ToOrgams for T where
T: TokenExt + MayHaveSpan + ListingElement + ToString + ?Sized,
T::DataAccess: ToOrgams,
T::Expr: ToOrgams,
T::TestKind: ToOrgams
{
fn to_orgams_string(&self) -> Result<Cow<str>, ToOrgamsError> {
// we assume it is already a BASM format and not an ORGAMS format
let handle_macro_definition = |token: &T| -> Cow<str> {
let macro_name = token.macro_definition_name();
let arguments_name = token.macro_definition_arguments();
let mut macro_content = token.macro_definition_code().to_owned();


for arg in arguments_name.iter() {
macro_content = macro_content.replace(&format!("{{{arg}}}"), arg);
}
Expand All @@ -55,7 +179,7 @@ impl<T: TokenExt + MayHaveSpan + ListingElement + Display> ToOrgams for T {
// also transform the content of the macro
// in case of failure, fallback to the original content
let macro_content = if let Ok(macro_content_listing) = parse_z80(&macro_content) {
let macro_content_listing = &macro_content_listing[..];
let macro_content_listing = macro_content_listing.as_slice();
macro_content_listing
.to_orgams_string()
.map(|s| s.to_string())
Expand Down Expand Up @@ -90,7 +214,7 @@ impl<T: TokenExt + MayHaveSpan + ListingElement + Display> ToOrgams for T {
repr.into()
};

let handle_standard_instruction = |token: &T| -> Cow<str> {
let handle_standard_directive = |token: &T| -> Cow<str> {
// if self.has_span() {
// Cow::borrowed(self.span().as_str())
// } else {
Expand All @@ -107,8 +231,61 @@ impl<T: TokenExt + MayHaveSpan + ListingElement + Display> ToOrgams for T {
s.into()
};

// XXX strong limitation, does not yet handle 3 args
let handle_opcode = |token: &T| -> String {
let mut op = token.mnemonic().unwrap().to_orgams_string().unwrap().to_string();

if let Some(arg) = token.mnemonic_arg1() {
op.push(' ');
op.push_str(&arg.to_orgams_string().unwrap())
}

if let Some(arg) = token.mnemonic_arg2() {
if token.mnemonic_arg1().is_some() {
op.push(',');
} else {
op.push(' ');
}
op.push_str(&arg.to_orgams_string().unwrap())
}

op

};

let handle_assign = |token: &T| -> String {
let label = token.assign_symbol();
let value = token.assign_value();

format!("{}={}", label, value.to_orgams_string().unwrap())
};

let handle_equ = |token: &T| -> String {
let label = token.equ_symbol();
let value = token.equ_value();

format!("{} EQU {}", label, value.to_orgams_string().unwrap())
};

let handle_if = |token: &T| -> String {
assert!(self.if_nb_tests() == 1);

let (test, code) = token.if_test(0);
let mut content = format!("{}\n{}", test.to_orgams_string().unwrap(), code.to_orgams_string().unwrap());

if let Some(code) = token.if_else() {
content.push_str("\n\tELSE\n");
content.push_str(&code.to_orgams_string().unwrap());
}

content.push_str("\n\tENDIF\n");
content
};

// This is the default behavior that changes nothing
let repr = if self.is_macro_definition() {
let repr = if self.is_opcode() {
Cow::owned(handle_opcode(self))
} else if self.is_macro_definition() {
handle_macro_definition(self)
}
else if self.is_print() {
Expand All @@ -117,8 +294,17 @@ impl<T: TokenExt + MayHaveSpan + ListingElement + Display> ToOrgams for T {
else if self.is_call_macro_or_build_struct() {
handle_macro_call(self)
}
else if self.is_assign() {
handle_assign(self).into()
}
else if self.is_equ(){
handle_equ(self).into()
}
else if self.is_if() {
handle_if(self).into()
}
else {
handle_standard_instruction(self)
handle_standard_directive(self)
};

if repr.is_empty() {
Expand Down Expand Up @@ -171,13 +357,7 @@ impl<T: ToOrgams> ToOrgams for &[T] {
}

// TODO do it properly by coding the complete expression display
let content = content.replace("0x", "&");

// TODO handle that in macro call
let content = content.replace("(void)", "()");

// TODO handle that directly in instruction print out
let content = content.replace(", ", ",");
// let content = content.replace("0x", "&");

Ok(content.into())
}
Expand All @@ -200,5 +380,5 @@ pub fn convert_source<P1: AsRef<Utf8Path>, P2: AsRef<Utf8Path>>(
let lst = lst.as_slice();
let orgams = lst.to_orgams_string()?;
std::fs::write(tgt, orgams.as_bytes())
.map_err(|e| format!("Error while saving {}", tgt).as_str().into())
.map_err(|e| format!("Error while saving {}. {}", tgt, e.to_string()).into())
}
21 changes: 19 additions & 2 deletions cpclib-asm/src/parser/obtained.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,8 @@ impl ListingElement for LocatedToken {
is_stuff_delegate!(is_print is_buildcpr is_label is_equ is_assign is_module is_directive is_rorg is_iterate is_for is_repeat_until is_repeat is_macro_definition is_if is_include is_incbin is_call_macro_or_build_struct is_function_definition is_crunched_section is_confined is_switch is_db is_dw is_str is_set is_comment is_org is_assembler_control is_while);

any_delegate!(
fn assign_symbol(&self) -> &str;
fn assign_value(&self) -> &Self::Expr;
fn equ_symbol(&self) -> &str;
fn equ_value(&self) -> &Self::Expr;
fn module_name(&self) -> &str;
Expand Down Expand Up @@ -1569,6 +1571,21 @@ impl ListingElement for LocatedTokenInner {
}
}


fn assign_symbol(&self) -> &str {
match &self {
LocatedTokenInner::Assign { label, .. } => label.as_str(),
_ => unreachable!()
}
}

fn assign_value(&self) -> &Self::Expr {
match &self {
LocatedTokenInner::Assign { expr, .. } => expr,
_ => unreachable!()
}
}

fn is_warning(&self) -> bool {
todo!()
}
Expand Down Expand Up @@ -2074,7 +2091,7 @@ impl ListingElement for LocatedTokenInner {

fn assembler_control_command(&self) -> &Self::AssemblerControlCommand {
match &self {
(LocatedTokenInner::AssemblerControl(cmd)) => cmd,
LocatedTokenInner::AssemblerControl(cmd) => cmd,
_ => unreachable!()
}
}
Expand All @@ -2101,7 +2118,7 @@ impl ListingElement for LocatedTokenInner {

fn macro_flavor(&self) -> AssemblerFlavor {
match self {
(LocatedTokenInner::Macro { flavor, .. }) => *flavor,
LocatedTokenInner::Macro { flavor, .. } => *flavor,
_ => unreachable!()
}
}
Expand Down
2 changes: 0 additions & 2 deletions cpclib-bndbuild/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ use cpclib_common::clap::*;
use cpclib_common::itertools::Itertools;
use cpclib_runner::runner::RunnerWithClap;
use lazy_regex::regex_captures;
use serde::de::IntoDeserializer;
use serde::Deserialize;
use task::Task;
use thiserror::Error;

Expand Down
4 changes: 1 addition & 3 deletions cpclib-bndbuild/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use std::fmt::Display;
use cpclib_common::itertools::Itertools;
use cpclib_runner::emucontrol::EMUCTRL_CMD;
use cpclib_runner::runner::assembler::{RasmVersion, RASM_CMD};
use cpclib_runner::runner::emulator::{
AceVersion, CpcecVersion, WinapeVersion, ACE_CMD, CPCEC_CMD, WINAPE_CMD
};
use cpclib_runner::runner::emulator::{ACE_CMD, CPCEC_CMD, WINAPE_CMD};
use cpclib_runner::runner::impdisc::IMPDISC_CMD;
use cpclib_runner::runner::martine::MARTINE_CMD;
use serde::de::{Error, Visitor};
Expand Down
1 change: 0 additions & 1 deletion cpclib-emucontrol/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::process::exit;
use std::time::Duration;

use clap::Parser;
use cpclib_runner::emucontrol::{handle_arguments, EmuCli};
Expand Down
2 changes: 0 additions & 2 deletions cpclib-runner/src/runner/emulator.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::path::PathBuf;

use cpclib_common::camino::Utf8PathBuf;
use directories::BaseDirs;

Expand Down
Loading

0 comments on commit 66a54f8

Please sign in to comment.