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_XOR,
|
||||
LSHIFT,
|
||||
RSHIFT
|
||||
RSHIFT,
|
||||
POWER
|
||||
};
|
||||
|
||||
Kind kind;
|
||||
|
|
@ -69,6 +70,8 @@ struct BinaryOperator
|
|||
return "<<";
|
||||
case RSHIFT:
|
||||
return ">>";
|
||||
case POWER:
|
||||
return "**";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
|
|
|
|||
151
src/codegen.hpp
151
src/codegen.hpp
|
|
@ -2,6 +2,27 @@
|
|||
#include "ast.hpp"
|
||||
#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
|
||||
{
|
||||
std::ostringstream output;
|
||||
|
|
@ -67,6 +88,7 @@ private:
|
|||
|
||||
if (!if_stmt->else_body.empty())
|
||||
{
|
||||
write_indent();
|
||||
write("else\n");
|
||||
indent_level++;
|
||||
for (const auto &s : if_stmt->else_body)
|
||||
|
|
@ -203,11 +225,27 @@ private:
|
|||
}
|
||||
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);
|
||||
}
|
||||
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))
|
||||
{
|
||||
|
|
@ -217,6 +255,117 @@ private:
|
|||
}
|
||||
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);
|
||||
write("(");
|
||||
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_PLUS; }
|
||||
\- { return yy::parser::token::TOK_MINUS; }
|
||||
\*\* { return yy::parser::token::TOK_POWER; }
|
||||
\* { return yy::parser::token::TOK_MULTIPLY; }
|
||||
\/ { return yy::parser::token::TOK_DIVIDE; }
|
||||
\% { 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>. { yymore(); }
|
||||
|
||||
f\" { yymore(); BEGIN(STRING_DQ); }
|
||||
\" { yymore(); BEGIN(STRING_DQ); }
|
||||
<STRING_DQ>\\\" { yymore(); }
|
||||
<STRING_DQ>\" { BEGIN(INITIAL); yylval->as<std::string>() = yytext; return yy::parser::token::TOK_STRING; }
|
||||
<STRING_DQ>. { yymore(); }
|
||||
|
||||
f\' { yymore(); BEGIN(STRING_SQ); }
|
||||
\' { yymore(); BEGIN(STRING_SQ); }
|
||||
<STRING_SQ>\\\' { yymore(); }
|
||||
<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 (ast_dump)
|
||||
{
|
||||
std::cout << "\n";
|
||||
}
|
||||
RubyGenerator generator;
|
||||
std::cout << generator.generate(*ast_root);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
%left PLUS MINUS
|
||||
%left MULTIPLY DIVIDE MODULO
|
||||
%left POWER
|
||||
|
||||
%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
|
||||
|
|
@ -124,6 +125,11 @@ expr:
|
|||
| 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_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)); }
|
||||
| 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)); }
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
print(x, y)
|
||||
print(x, y, "\n")
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
for i in items
|
||||
print(i)
|
||||
print(i, "\n")
|
||||
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