some progress
This commit is contained in:
parent
5c9abff73f
commit
f92f5ef7f6
11 changed files with 235 additions and 4 deletions
3
shortcomings.md
Normal file
3
shortcomings.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
- string processing is very primitive, it just checks for f at the beggining, and then adds #, before { if so
|
||||||
|
- no elif
|
||||||
|
- no lambdas
|
||||||
|
|
@ -22,7 +22,8 @@ struct BinaryOperator
|
||||||
BIT_OR,
|
BIT_OR,
|
||||||
BIT_XOR,
|
BIT_XOR,
|
||||||
LSHIFT,
|
LSHIFT,
|
||||||
RSHIFT
|
RSHIFT,
|
||||||
|
POWER
|
||||||
};
|
};
|
||||||
|
|
||||||
Kind kind;
|
Kind kind;
|
||||||
|
|
@ -69,6 +70,8 @@ struct BinaryOperator
|
||||||
return "<<";
|
return "<<";
|
||||||
case RSHIFT:
|
case RSHIFT:
|
||||||
return ">>";
|
return ">>";
|
||||||
|
case POWER:
|
||||||
|
return "**";
|
||||||
default:
|
default:
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
151
src/codegen.hpp
151
src/codegen.hpp
|
|
@ -2,6 +2,27 @@
|
||||||
#include "ast.hpp"
|
#include "ast.hpp"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
// greatly simplified
|
||||||
|
std::string convert_string(std::string input)
|
||||||
|
{
|
||||||
|
std::ostringstream output;
|
||||||
|
for (int i = 1; i < input.size(); i++)
|
||||||
|
{
|
||||||
|
if (input[i] != '{')
|
||||||
|
{
|
||||||
|
output << input[i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (input[i - 1] != '\\')
|
||||||
|
{
|
||||||
|
output << "#{";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
output << input[i];
|
||||||
|
}
|
||||||
|
return output.str();
|
||||||
|
}
|
||||||
|
|
||||||
class RubyGenerator
|
class RubyGenerator
|
||||||
{
|
{
|
||||||
std::ostringstream output;
|
std::ostringstream output;
|
||||||
|
|
@ -67,6 +88,7 @@ private:
|
||||||
|
|
||||||
if (!if_stmt->else_body.empty())
|
if (!if_stmt->else_body.empty())
|
||||||
{
|
{
|
||||||
|
write_indent();
|
||||||
write("else\n");
|
write("else\n");
|
||||||
indent_level++;
|
indent_level++;
|
||||||
for (const auto &s : if_stmt->else_body)
|
for (const auto &s : if_stmt->else_body)
|
||||||
|
|
@ -203,11 +225,27 @@ private:
|
||||||
}
|
}
|
||||||
else if (auto *id = dynamic_cast<const Identifier *>(&expr))
|
else if (auto *id = dynamic_cast<const Identifier *>(&expr))
|
||||||
{
|
{
|
||||||
|
std::string ident = id->name;
|
||||||
|
if (ident == "True")
|
||||||
|
{
|
||||||
|
output << "true";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ident == "False")
|
||||||
|
{
|
||||||
|
output << "false";
|
||||||
|
return;
|
||||||
|
}
|
||||||
write(id->name);
|
write(id->name);
|
||||||
}
|
}
|
||||||
else if (auto *str = dynamic_cast<const String *>(&expr))
|
else if (auto *str = dynamic_cast<const String *>(&expr))
|
||||||
{
|
{
|
||||||
write(str->value);
|
std::string value = str->value;
|
||||||
|
if (value[0] == 'f')
|
||||||
|
{
|
||||||
|
value = convert_string(value);
|
||||||
|
}
|
||||||
|
output << value;
|
||||||
}
|
}
|
||||||
else if (auto *binop = dynamic_cast<const BinOp *>(&expr))
|
else if (auto *binop = dynamic_cast<const BinOp *>(&expr))
|
||||||
{
|
{
|
||||||
|
|
@ -217,6 +255,117 @@ private:
|
||||||
}
|
}
|
||||||
else if (auto *call = dynamic_cast<const Call *>(&expr))
|
else if (auto *call = dynamic_cast<const Call *>(&expr))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (auto *func_id = dynamic_cast<const Identifier *>(call->func.get()))
|
||||||
|
{
|
||||||
|
if (func_id->name == "range")
|
||||||
|
{
|
||||||
|
// Handle range() specially for for loops
|
||||||
|
if (call->args.size() == 1)
|
||||||
|
{
|
||||||
|
// range(stop) -> 0...stop
|
||||||
|
write("0...");
|
||||||
|
generate_expr(*call->args[0]);
|
||||||
|
}
|
||||||
|
else if (call->args.size() == 2)
|
||||||
|
{
|
||||||
|
// range(start, stop) -> start...stop
|
||||||
|
generate_expr(*call->args[0]);
|
||||||
|
write("...");
|
||||||
|
generate_expr(*call->args[1]);
|
||||||
|
}
|
||||||
|
else if (call->args.size() == 3)
|
||||||
|
{
|
||||||
|
// range(start, stop, step) - need custom handling
|
||||||
|
write("(");
|
||||||
|
generate_expr(*call->args[0]);
|
||||||
|
write("...");
|
||||||
|
generate_expr(*call->args[1]);
|
||||||
|
write(").step(");
|
||||||
|
generate_expr(*call->args[2]);
|
||||||
|
write(")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback to regular call
|
||||||
|
write("range(");
|
||||||
|
for (size_t i = 0; i < call->args.size(); i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
write(", ");
|
||||||
|
generate_expr(*call->args[i]);
|
||||||
|
}
|
||||||
|
write(")");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (func_id->name == "int")
|
||||||
|
{
|
||||||
|
// int(x) -> Integer(x)
|
||||||
|
write("Integer(");
|
||||||
|
if (!call->args.empty())
|
||||||
|
{
|
||||||
|
generate_expr(*call->args[0]);
|
||||||
|
}
|
||||||
|
write(")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (func_id->name == "float")
|
||||||
|
{
|
||||||
|
// float(x) -> Float(x)
|
||||||
|
write("Float(");
|
||||||
|
if (!call->args.empty())
|
||||||
|
{
|
||||||
|
generate_expr(*call->args[0]);
|
||||||
|
}
|
||||||
|
write(")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (func_id->name == "str")
|
||||||
|
{
|
||||||
|
// str(x) -> x.to_s
|
||||||
|
if (!call->args.empty())
|
||||||
|
{
|
||||||
|
generate_expr(*call->args[0]);
|
||||||
|
write(".to_s");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write("\"\"");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (func_id->name == "len")
|
||||||
|
{
|
||||||
|
// len(x) -> x.length or x.size
|
||||||
|
if (!call->args.empty())
|
||||||
|
{
|
||||||
|
generate_expr(*call->args[0]);
|
||||||
|
write(".length");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write("0");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (func_id->name == "print")
|
||||||
|
{
|
||||||
|
write("print(");
|
||||||
|
if (!call->args.empty())
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < call->args.size(); i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
write(", ");
|
||||||
|
generate_expr(*call->args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(", \"\\n\")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generate_expr(*call->func);
|
generate_expr(*call->func);
|
||||||
write("(");
|
write("(");
|
||||||
for (size_t i = 0; i < call->args.size(); i++)
|
for (size_t i = 0; i < call->args.size(); i++)
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ continue { return yy::parser::token::TOK_KW_CONTINUE; }
|
||||||
\>\>\= { return yy::parser::token::TOK_RSHIFT_ASSIGN; }
|
\>\>\= { return yy::parser::token::TOK_RSHIFT_ASSIGN; }
|
||||||
\+ { return yy::parser::token::TOK_PLUS; }
|
\+ { return yy::parser::token::TOK_PLUS; }
|
||||||
\- { return yy::parser::token::TOK_MINUS; }
|
\- { return yy::parser::token::TOK_MINUS; }
|
||||||
|
\*\* { return yy::parser::token::TOK_POWER; }
|
||||||
\* { return yy::parser::token::TOK_MULTIPLY; }
|
\* { return yy::parser::token::TOK_MULTIPLY; }
|
||||||
\/ { return yy::parser::token::TOK_DIVIDE; }
|
\/ { return yy::parser::token::TOK_DIVIDE; }
|
||||||
\% { return yy::parser::token::TOK_MODULO; }
|
\% { return yy::parser::token::TOK_MODULO; }
|
||||||
|
|
@ -100,11 +101,13 @@ continue { return yy::parser::token::TOK_KW_CONTINUE; }
|
||||||
<STRING_TSQ>\'\'\' { BEGIN(INITIAL); yylval->as<std::string>() = yytext; return yy::parser::token::TOK_STRING; }
|
<STRING_TSQ>\'\'\' { BEGIN(INITIAL); yylval->as<std::string>() = yytext; return yy::parser::token::TOK_STRING; }
|
||||||
<STRING_TSQ>. { yymore(); }
|
<STRING_TSQ>. { yymore(); }
|
||||||
|
|
||||||
|
f\" { yymore(); BEGIN(STRING_DQ); }
|
||||||
\" { yymore(); BEGIN(STRING_DQ); }
|
\" { yymore(); BEGIN(STRING_DQ); }
|
||||||
<STRING_DQ>\\\" { yymore(); }
|
<STRING_DQ>\\\" { yymore(); }
|
||||||
<STRING_DQ>\" { BEGIN(INITIAL); yylval->as<std::string>() = yytext; return yy::parser::token::TOK_STRING; }
|
<STRING_DQ>\" { BEGIN(INITIAL); yylval->as<std::string>() = yytext; return yy::parser::token::TOK_STRING; }
|
||||||
<STRING_DQ>. { yymore(); }
|
<STRING_DQ>. { yymore(); }
|
||||||
|
|
||||||
|
f\' { yymore(); BEGIN(STRING_SQ); }
|
||||||
\' { yymore(); BEGIN(STRING_SQ); }
|
\' { yymore(); BEGIN(STRING_SQ); }
|
||||||
<STRING_SQ>\\\' { yymore(); }
|
<STRING_SQ>\\\' { yymore(); }
|
||||||
<STRING_SQ>\' { BEGIN(INITIAL); yylval->as<std::string>() = yytext; return yy::parser::token::TOK_STRING; }
|
<STRING_SQ>\' { BEGIN(INITIAL); yylval->as<std::string>() = yytext; return yy::parser::token::TOK_STRING; }
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,10 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
if (write_ruby)
|
if (write_ruby)
|
||||||
{
|
{
|
||||||
|
if (ast_dump)
|
||||||
|
{
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
RubyGenerator generator;
|
RubyGenerator generator;
|
||||||
std::cout << generator.generate(*ast_root);
|
std::cout << generator.generate(*ast_root);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
|
|
||||||
%left PLUS MINUS
|
%left PLUS MINUS
|
||||||
%left MULTIPLY DIVIDE MODULO
|
%left MULTIPLY DIVIDE MODULO
|
||||||
|
%left POWER
|
||||||
|
|
||||||
%right ASSIGN PLUS_ASSIGN MINUS_ASSIGN MULTIPLY_ASSIGN DIVIDE_ASSIGN MODULO_ASSIGN
|
%right ASSIGN PLUS_ASSIGN MINUS_ASSIGN MULTIPLY_ASSIGN DIVIDE_ASSIGN MODULO_ASSIGN
|
||||||
%right BIT_AND_ASSIGN BIT_OR_ASSIGN BIT_XOR_ASSIGN LSHIFT_ASSIGN RSHIFT_ASSIGN
|
%right BIT_AND_ASSIGN BIT_OR_ASSIGN BIT_XOR_ASSIGN LSHIFT_ASSIGN RSHIFT_ASSIGN
|
||||||
|
|
@ -124,6 +125,11 @@ expr:
|
||||||
| expr LT expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::LT) , std::move($1), std::move($3)); }
|
| expr LT expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::LT) , std::move($1), std::move($3)); }
|
||||||
| expr KW_AND expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::AND) , std::move($1), std::move($3)); }
|
| expr KW_AND expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::AND) , std::move($1), std::move($3)); }
|
||||||
| expr KW_OR expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::OR) , std::move($1), std::move($3)); }
|
| expr KW_OR expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::OR) , std::move($1), std::move($3)); }
|
||||||
|
| expr LTE expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::LTE) , std::move($1), std::move($3)); }
|
||||||
|
| expr POWER expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::POWER) , std::move($1), std::move($3)); }
|
||||||
|
| expr MODULO expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::MOD) , std::move($1), std::move($3)); }
|
||||||
|
| expr EQ expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::EQ) , std::move($1), std::move($3)); }
|
||||||
|
| expr DIVIDE expr { $$ = std::make_unique<BinOp>( BinaryOperator(BinaryOperator::DIV) , std::move($1), std::move($3)); }
|
||||||
| KW_NOT expr { $$ = std::make_unique<UnaryOpExpr>( UnaryOperator(UnaryOperator::NOT) , std::move($2)); }
|
| KW_NOT expr { $$ = std::make_unique<UnaryOpExpr>( UnaryOperator(UnaryOperator::NOT) , std::move($2)); }
|
||||||
| expr L_BRACKET expr R_BRACKET { $$ = std::make_unique<Subscript>(std::move($1), std::move($3));}
|
| expr L_BRACKET expr R_BRACKET { $$ = std::make_unique<Subscript>(std::move($1), std::move($3));}
|
||||||
| expr L_BRACKET slice R_BRACKET{ $$ = std::make_unique<SliceSubscript>(std::move($1), std::move($3)); }
|
| expr L_BRACKET slice R_BRACKET{ $$ = std::make_unique<SliceSubscript>(std::move($1), std::move($3)); }
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
print(x, y)
|
print(x, y, "\n")
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
for i in items
|
for i in items
|
||||||
print(i)
|
print(i, "\n")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
23
test/ruby/23.out
Normal file
23
test/ruby/23.out
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
def factorial(n)
|
||||||
|
"""Calculate factorial recursively"""
|
||||||
|
if n <= 1
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return n * factorial(n - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
def is_prime(num)
|
||||||
|
if num < 2
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for i in 2...Integer(num ** 0.5) + 1
|
||||||
|
if num % i == 0
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
print("Factorial of 5: #{factorial(5)}", "\n")
|
||||||
|
for n in [2, 3, 4, 17, 21]
|
||||||
|
print("#{n} is prime: #{is_prime(n)}", "\n")
|
||||||
|
end
|
||||||
20
test/ruby/24.in
Normal file
20
test/ruby/24.in
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
def calculate_bmi(weight, height):
|
||||||
|
bmi = weight / (height ** 2)
|
||||||
|
|
||||||
|
if bmi < 18.5:
|
||||||
|
category = "Underweight"
|
||||||
|
else:
|
||||||
|
if bmi < 25:
|
||||||
|
category = "Normal"
|
||||||
|
else:
|
||||||
|
if bmi < 30:
|
||||||
|
category = "Overweight"
|
||||||
|
else:
|
||||||
|
category = "Obese"
|
||||||
|
|
||||||
|
return f"BMI: {bmi}, Category: {category}"
|
||||||
|
|
||||||
|
# Test
|
||||||
|
print(calculate_bmi(70, 1.75))
|
||||||
|
print(calculate_bmi(90, 1.80))
|
||||||
|
print(calculate_bmi(50, 1.65))
|
||||||
20
test/ruby/24.out
Normal file
20
test/ruby/24.out
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
def calculate_bmi(weight, height)
|
||||||
|
bmi = weight / height ** 2
|
||||||
|
if bmi < 18.5
|
||||||
|
category = "Underweight"
|
||||||
|
else
|
||||||
|
if bmi < 25
|
||||||
|
category = "Normal"
|
||||||
|
else
|
||||||
|
if bmi < 30
|
||||||
|
category = "Overweight"
|
||||||
|
else
|
||||||
|
category = "Obese"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return "BMI: #{bmi}, Category: #{category}"
|
||||||
|
end
|
||||||
|
print(calculate_bmi(70, 1.75), "\n")
|
||||||
|
print(calculate_bmi(90, 1.80), "\n")
|
||||||
|
print(calculate_bmi(50, 1.65), "\n")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue