-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add forward-declarations preprocessor * Add Pascal templates * Support `case_insensitive_keywords` option in stub_config.toml --------- Co-authored-by: ellnix <[email protected]> Co-authored-by: Andriamanitra <[email protected]>
- Loading branch information
1 parent
33a84d3
commit 88685b5
Showing
17 changed files
with
329 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{{ ident }} : {{ type_tokens[var_type] }};{% if input_comment %} // {{ input_comment }} {% endif %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
for {{ index_ident }} := 0 to {{ count_var }} - 1 do | ||
begin | ||
{%- for line in inner %} | ||
{{line}} | ||
{%- endfor %} | ||
end; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{%- set vars_length = vars | length -%} | ||
{%- if vars_length == 1 -%} | ||
{%- set offset = "" -%} | ||
{%- else -%} | ||
{%- set offset = vars_length ~ "*" -%} | ||
{%- endif -%} | ||
|
||
ParseIn(Inputs); | ||
for {{ index_ident }} := 0 to {{ count_var }} - 1 do | ||
begin | ||
{%- for var in vars %} | ||
{%- if loop.index0 == 0 -%} | ||
{%- set idx = "" -%} | ||
{%- else -%} | ||
{%- set idx = "+" ~ loop.index0 -%} | ||
{%- endif -%} | ||
{%- if var.var_type == "Word" -%} | ||
{%- set assign_var = var.ident ~ " := Inputs[" ~ offset ~ index_ident ~ idx ~ "];" -%} | ||
{%- else -%} | ||
{%- set assign_var = var.ident ~ " := " ~ type_parsers[var.var_type] ~ "(Inputs[" ~ offset ~ index_ident ~ idx ~ "]);" -%} | ||
{%- endif %} | ||
{{ assign_var }} | ||
{%- endfor %} | ||
end; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{% for line in statement %} | ||
// {{ line }} | ||
{%- endfor %} | ||
{% for line in code_lines %} | ||
{{ line }} | ||
{%- endfor %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
program Answer; | ||
{$H+} | ||
uses sysutils, classes, math; | ||
|
||
// Helper to read a line and split tokens | ||
procedure ParseIn(Inputs: TStrings) ; | ||
var Line : string; | ||
begin | ||
readln(Line); | ||
Inputs.Clear; | ||
Inputs.Delimiter := ' '; | ||
Inputs.DelimitedText := Line; | ||
end; | ||
|
||
var | ||
{%- for line in forward_declarations %} | ||
{{ line }} | ||
{%- endfor %} | ||
Inputs : TStringList; | ||
begin | ||
Inputs := TStringList.Create; | ||
{%- for line in main_contents %} | ||
{{ line }} | ||
{%- endfor %} | ||
end. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
ParseIn(Inputs); | ||
{% for var in vars -%} | ||
{%- if var.var_type == "Word" -%} | ||
{%- set assign_var = var.ident ~ " := Inputs[" ~ loop.index0 ~ "];" -%} | ||
{%- else -%} | ||
{%- set assign_var = var.ident ~ " := " ~ type_parsers[var.var_type] ~ "(Inputs[" ~ loop.index0 ~ "]);" -%} | ||
{%- endif -%} | ||
{{ assign_var }} | ||
{% endfor -%} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{%- if var.var_type == "String" -%} | ||
{%- set readln = "readln(" ~ var.ident ~ ");" -%} | ||
{%- else -%} | ||
{%- set parse_input = "ParseIn(Inputs);" -%} | ||
{%- if var.var_type == "Word" -%} | ||
{%- set assign_var = var.ident ~ " := Inputs[0];" -%} | ||
{%- else -%} | ||
{%- set assign_var = var.ident ~ " := " ~ type_parsers[var.var_type] ~ "(Inputs[0]);" -%} | ||
{%- endif -%} | ||
{%- endif -%} | ||
|
||
{%- if var.var_type == "String" -%} | ||
{{ readln }} | ||
{% else -%} | ||
{{ parse_input }} | ||
{{ assign_var }} | ||
{% endif -%} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
name = "pascal" | ||
source_file_ext = "pas" | ||
|
||
preprocessor = "forward-declarations" | ||
|
||
[type_tokens] | ||
Int = "Int32" | ||
Long = "Int64" | ||
Float = "Extended" | ||
Bool = "Int32" | ||
String = "String" | ||
Word = "String" | ||
|
||
[type_parsers] | ||
Int = "StrToInt" | ||
Long = "StrToInt64" | ||
Float = "StrToFloat" | ||
Bool = "StrToInt" | ||
|
||
[variable_name_options] | ||
casing = "pascal_case" | ||
allow_uppercase_vars = false | ||
keywords = [ | ||
# Special CG variables. Inputs is a buffer-like variable used for parsing, | ||
# and Answer is the name of the program. | ||
"inputs", "answer", | ||
|
||
# Others | ||
"boolean", | ||
|
||
# https://wiki.freepascal.org/Reserved_words#Reserved_words_in_Turbo_Pascal | ||
"and", "array", "asm", "begin", "break", "case", "const", "constructor", | ||
"continue", "destructor", "div", "do", "downto", "else", "end", | ||
"false", "file", "for", "function", "goto", "if", "implementation", | ||
"in", "inline", "interface", "label", "mod", "nil", "not", "object", | ||
"of", "on", "operator", "or", "packed", "procedure", "program", "record", | ||
"repeat", "set", "shl", "shr", "string", "then", "to", "true", "type", | ||
"unit", "until", "uses", "var", "while", "with", "xor", | ||
|
||
# https://wiki.freepascal.org/Reserved_words#Reserved_words_in_Object_Pascal | ||
"as", "class", "constref", "dispose", "except", "exit", "exports", | ||
"finalization", "finally", "inherited", "initialization", "is", "library", | ||
"new", "on", "out", "property", "raise", "self", "threadvar", "try", | ||
|
||
# https://wiki.freepascal.org/Reserved_words#Modifiers_(directives) | ||
"absolute", "abstract", "alias", "assembler", "cdecl", "Cppdecl", | ||
"default", "export", "external", "forward", "generic", "index", "local", | ||
"name", "nostackframe", "oldfpccall", "override", "pascal", "private", | ||
"protected", "public", "published", "read", "register", "reintroduce", | ||
"safecall", "softfloat", "specialize", "stdcall", "virtual", "write" | ||
] | ||
case_insensitive_keywords = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{%- for line in output_comments %} | ||
// {{ line }} | ||
{% endfor %} | ||
{%- for line in messages -%} | ||
writeln('{{ line | replace(from="'", to="''") }}'); | ||
{% endfor -%} | ||
flush(StdErr); flush(output); // Codingame compliance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
// UNSUPPORTED WRITE_JOIN |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pub mod forward_declarations; | ||
pub mod lisp_like; | ||
|
||
use dyn_clone::DynClone; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
use super::Renderable; | ||
use crate::stub::renderer::ALPHABET; | ||
use crate::stub::{Cmd, Stub, VarType, VariableCommand}; | ||
|
||
/// Change the Stub structure into: [ReadDeclarations, MainContents(old_cmds)] | ||
/// This is relevant for Pascal. | ||
#[derive(Debug, Clone)] | ||
struct MainWrapper { | ||
// Read declarations that should go on top of the main function. | ||
// render declaration: int c; | ||
// render read (usual): int c;\nscanf("%d", c); | ||
pub forward_declarations: Vec<VariableCommand>, | ||
// The main function contents. | ||
pub main_content: Vec<Cmd>, | ||
} | ||
|
||
/// Edit stub to allow for Pascal-style forward declarations. | ||
/// | ||
/// Wraps all of the commands in a stub that contains: | ||
/// - Forward declarations | ||
/// - The rest of the code | ||
/// | ||
/// Traverses through the stub commands, taking all declared variables. | ||
/// Leaves only one MainWrapper command in the stub. | ||
/// Introduces two new templates: | ||
/// - `forward_declaration` - similar to a read_one declares one single | ||
/// variable, includes all the fields in a VariableCommand (not nested under | ||
/// `var`) | ||
/// - `main_wrapper` - wraps all of the code, contains `forward_declarations` | ||
/// (the above resource, rendered) and `main_content` | ||
pub fn transform(stub: &mut Stub) { | ||
let mut max_nested_depth = 0; | ||
|
||
let mut forward_declarations: Vec<VariableCommand> = stub | ||
.commands | ||
.iter() | ||
.filter_map(|cmd| { | ||
let (cmd, nested_depth) = unpack_cmd(cmd, 0); | ||
|
||
if nested_depth > max_nested_depth { | ||
max_nested_depth = nested_depth; | ||
} | ||
|
||
match cmd { | ||
Cmd::LoopLine { | ||
variables: var_cmds, .. | ||
} => Some(var_cmds.into_iter()), | ||
Cmd::Read(var_cmds) => Some(var_cmds.into_iter()), | ||
_ => None, | ||
} | ||
}) | ||
.flatten() | ||
.collect(); | ||
|
||
// Add the loop indices to the declarations | ||
forward_declarations.extend(ALPHABET[0..max_nested_depth].iter().map(|loop_var| VariableCommand { | ||
ident: loop_var.to_string(), | ||
var_type: VarType::Int, | ||
max_length: None, | ||
input_comment: String::new(), | ||
})); | ||
|
||
let mut seen = std::collections::BTreeSet::<String>::new(); | ||
forward_declarations.retain(|var_cmd| seen.insert(var_cmd.ident.clone())); | ||
|
||
let wrapper = MainWrapper { | ||
forward_declarations, | ||
main_content: stub.commands.drain(..).collect(), | ||
}; | ||
|
||
stub.commands = vec![Cmd::External(Box::new(wrapper))]; | ||
} | ||
|
||
fn unpack_cmd(cmd: &Cmd, nested_depth: usize) -> (Cmd, usize) { | ||
match cmd { | ||
Cmd::Loop { | ||
count_var: _, | ||
command: subcmd, | ||
} => unpack_cmd(subcmd, nested_depth + 1), | ||
Cmd::LoopLine { .. } => (cmd.clone(), nested_depth + 1), | ||
_ => (cmd.clone(), nested_depth), | ||
} | ||
} | ||
|
||
impl Renderable for MainWrapper { | ||
fn render(&self, renderer: &crate::stub::renderer::Renderer) -> String { | ||
let main_contents_str: String = | ||
self.main_content.iter().map(|cmd| renderer.render_command(cmd, 0)).collect(); | ||
let main_contents: Vec<&str> = main_contents_str.lines().collect(); | ||
|
||
let forward_declarations: Vec<String> = | ||
self.forward_declarations.iter().map(|vc| vc.render(renderer)).collect(); | ||
|
||
let mut context = tera::Context::new(); | ||
context.insert("forward_declarations", &forward_declarations); | ||
context.insert("main_contents", &main_contents); | ||
renderer.tera_render("main_wrapper", &mut context) | ||
} | ||
} | ||
|
||
impl Renderable for VariableCommand { | ||
fn render(&self, renderer: &crate::stub::renderer::Renderer) -> String { | ||
let mut context = | ||
tera::Context::from_serialize(self).expect("VariableCommand should be serializable"); | ||
context.insert("ident", &renderer.lang.variable_name_options.transform_variable_name(&self.ident)); | ||
renderer.tera_render("forward_declarations", &mut context).trim().to_string() | ||
} | ||
} |
Oops, something went wrong.