Skip to content

Commit f45f2a7

Browse files
authored
Add Method Chaining (#216)
* Añadir el método de encadenamiento * Implementing http * v0.1.4-pre-beta
1 parent d2c0702 commit f45f2a7

File tree

8 files changed

+272
-4
lines changed

8 files changed

+272
-4
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "wavec"
3-
version = "0.1.4-pre-beta-nightly-2025-07-16"
3+
version = "0.1.4-pre-beta"
44
edition = "2021"
55

66
# [target.x86_64-apple-darwin]

front/lexer/src/lexer/lexer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ impl<'a> Lexer<'a> {
509509
line: self.line,
510510
}
511511
},
512-
'a'..='z' | 'A'..='Z' => {
512+
'a'..='z' | 'A'..='Z' | '_' => {
513513
let identifier = self.identifier();
514514
match identifier.as_str() {
515515
"fun" => {

front/parser/src/parser/ast.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ pub enum Expression {
7878
name: String,
7979
args: Vec<Expression>,
8080
},
81+
MethodCall {
82+
object: Box<Expression>,
83+
name: String,
84+
args: Vec<Expression>,
85+
},
8186
Literal(Literal),
8287
Variable(String),
8388
Deref(Box<Expression>),

front/parser/src/parser/format.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ where
213213
{
214214
let token = tokens.peek()?.clone();
215215

216-
match &token.token_type {
216+
let mut expr = match &token.token_type {
217217
TokenType::Number(value) => {
218218
tokens.next();
219219
Some(Expression::Literal(Literal::Number(*value)))
@@ -455,7 +455,71 @@ where
455455
}
456456
}
457457
}
458+
};
459+
460+
loop {
461+
match tokens.peek().map(|t| &t.token_type) {
462+
Some(TokenType::Dot) => {
463+
tokens.next();
464+
465+
let name = if let Some(Token { token_type: TokenType::Identifier(name), .. }) = tokens.next() {
466+
name.clone()
467+
} else {
468+
println!("Error: Expected identifier after Dot");
469+
return None;
470+
};
471+
472+
if tokens.peek().map_or(true, |t| t.token_type != TokenType::Lparen) {
473+
println!("Error: Expected '(' for method call");
474+
return None;
475+
}
476+
tokens.next();
477+
478+
let mut args = vec![];
479+
if tokens.peek().map_or(false, |t| t.token_type != TokenType::Rparen) {
480+
loop {
481+
let arg = parse_expression(tokens)?;
482+
args.push(arg);
483+
484+
if let Some(Token { token_type: TokenType::Comma, .. }) = tokens.peek() {
485+
tokens.next();
486+
} else {
487+
break;
488+
}
489+
}
490+
}
491+
492+
if tokens.peek().map_or(true, |t| t.token_type != TokenType::Rparen) {
493+
println!("Error: Expected ')' after method call arguments");
494+
return None;
495+
}
496+
tokens.next();
497+
498+
expr = Some(Expression::MethodCall {
499+
object: Box::new(expr?),
500+
name,
501+
args,
502+
});
503+
}
504+
Some(TokenType::Lbrack) => {
505+
tokens.next();
506+
let index_expr = parse_expression(tokens)?;
507+
if tokens.peek().map_or(true, |t| t.token_type != TokenType::Rbrack) {
508+
println!("Error: Expected ']' after index");
509+
return None;
510+
}
511+
tokens.next();
512+
expr = Some(Expression::IndexAccess {
513+
target: Box::new(expr?),
514+
index: Box::new(index_expr),
515+
});
516+
}
517+
_ => {
518+
break;
519+
}
520+
}
458521
}
522+
Some(expr?)
459523
}
460524

461525
pub fn parse_parenthesized_expression<'a, T>(tokens: &mut Peekable<T>) -> Option<Expression>

llvm_temporary/src/llvm_temporary/expression.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,43 @@ pub fn generate_expression_ir<'ctx>(
175175
}
176176
}
177177

178+
Expression::MethodCall { object, name, args } => {
179+
let function = module
180+
.get_function(name)
181+
.unwrap_or_else(|| panic!("Function '{}' not found as a global function", name));
182+
183+
let function_type = function.get_type();
184+
let param_types: Vec<BasicTypeEnum> = function_type
185+
.get_param_types()
186+
.iter()
187+
.map(|t| (*t).into())
188+
.collect();
189+
190+
let object_expected_type = param_types.get(0).copied();
191+
let object_val = generate_expression_ir(context, builder, object, variables, module, object_expected_type);
192+
193+
let mut compiled_args: Vec<inkwell::values::BasicMetadataValueEnum<'ctx>> = vec![object_val.into()];
194+
195+
for (i, arg) in args.iter().enumerate() {
196+
let expected = param_types.get(i + 1).copied();
197+
let val = generate_expression_ir(context, builder, arg, variables, module, expected);
198+
199+
compiled_args.push(val.into());
200+
}
201+
202+
let call_site = builder.build_call(function, &compiled_args, &format!("call_{}", name)).unwrap();
203+
204+
if function_type.get_return_type().is_some() {
205+
if let Some(ret_val) = call_site.try_as_basic_value().left() {
206+
ret_val
207+
} else {
208+
panic!("Method '{}' should return a value but didn't", name);
209+
}
210+
} else {
211+
context.i32_type().const_zero().as_basic_value_enum()
212+
}
213+
}
214+
178215
Expression::AssignOperation { target, operator, value } => {
179216
let ptr = generate_address_ir(context, builder, target, variables, module);
180217

llvm_temporary/src/llvm_temporary/statement.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ pub fn generate_statement_ir<'ctx>(
183183
let val = generate_expression_ir(context, builder, init, variables, module, Some(llvm_type));
184184
builder.build_store(alloca, val).unwrap();
185185
}
186-
(Expression::FunctionCall { .. }, _) => {
186+
(Expression::FunctionCall { .. } | Expression::MethodCall { .. }, _) => {
187187
let val = generate_expression_ir(context, builder, init, variables, module, Some(llvm_type));
188188
builder.build_store(alloca, val).unwrap();
189189
}

test/test55.wave

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
fun len(s: str) -> i32 {
2+
var count: i32 = 0;
3+
while (s[count] != 0) {
4+
count += 1;
5+
}
6+
return count;
7+
}
8+
9+
// num.add(val) -> add(num, val)
10+
fun add(self: i32, value: i32) -> i32 {
11+
return self + value;
12+
}
13+
14+
fun subtract(self: i32, value: i32) -> i32 {
15+
return self - value;
16+
}
17+
18+
fun main() {
19+
println("--- Test 55: Method Chaining ---");
20+
21+
println("\n[1. Simple Method Call]");
22+
var my_string: str = "Hello from Wave's Chaining API!";
23+
println("Testing string: '{}'", my_string);
24+
25+
var length: i32 = my_string.len();
26+
println("Result of my_string.len(): {}", length);
27+
28+
println("\n[2. Chained Method Calls]");
29+
var num: i32 = 10;
30+
println("Initial number: {}", num);
31+
32+
var chained_result: i32 = num.add(5).subtract(3);
33+
println("Result of num.add(5).subtract(3): {}", chained_result);
34+
35+
println("\n--- Test 55 Finished ---");
36+
}

test/test56.wave

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
fun syscall1(id: i64) -> i64 {
2+
var ret_val: i64;
3+
asm {
4+
"syscall"
5+
in("rax") id
6+
out("rax") ret_val
7+
}
8+
return ret_val;
9+
}
10+
11+
fun syscall2(id: i64, arg1: i64) -> i64 {
12+
var ret_val: i64;
13+
asm {
14+
"syscall"
15+
in("rax") id
16+
in("rdi") arg1
17+
out("rax") ret_val
18+
}
19+
return ret_val;
20+
}
21+
22+
fun syscall3(id: i64, arg1: i64, arg2: i64) -> i64 {
23+
var ret_val: i64;
24+
asm {
25+
"syscall"
26+
in("rax") id
27+
in("rdi") arg1
28+
in("rsi") arg2
29+
out("rax") ret_val
30+
}
31+
return ret_val;
32+
}
33+
34+
fun syscall4(id: i64, arg1: i64, arg2: i64, arg3: i64) -> i64 {
35+
var ret_val: i64;
36+
asm {
37+
"syscall"
38+
in("rax") id
39+
in("rdi") arg1
40+
in("rsi") arg2
41+
in("rdx") arg3
42+
out("rax") ret_val
43+
}
44+
return ret_val;
45+
}
46+
47+
fun _socket_create() -> i32 {
48+
return syscall4(41, 2, 1, 0);
49+
}
50+
51+
fun _socket_bind(sockfd: i32, ip_addr: i32, port: i16) -> i32 {
52+
asm {
53+
out("rax") result
54+
in("rdi") sockfd
55+
}
56+
return result;
57+
}
58+
59+
fun _socket_listen(sockfd: i32, backlog: i32) -> i32 {
60+
return syscall3(50, sockfd, backlog);
61+
}
62+
63+
fun _socket_close(sockfd: i32) {
64+
syscall2(3, sockfd);
65+
}
66+
67+
fun new_server(ip_str: str, port: i16) -> ptr<i32> {
68+
var sockfd: i32 = _socket_create();
69+
if (sockfd < 0) {
70+
println("Error: Failed to create socket.");
71+
return 0;
72+
}
73+
74+
if (_socket_bind(sockfd, 0, port) < 0) {
75+
println("Error: Failed to bind socket.");
76+
_socket_close(sockfd);
77+
return 0;
78+
}
79+
80+
return sockfd;
81+
}
82+
83+
fun listen(server_fd: i32, backlog: i32) -> i32 {
84+
if (_socket_listen(server_fd, backlog) < 0) {
85+
println("Error: Failed to listen on socket.");
86+
return -1;
87+
}
88+
println("Server is listening...");
89+
return server_fd;
90+
}
91+
92+
fun start(server_fd: i32) {
93+
println("Server accepting connections...");
94+
95+
while (true) {
96+
var client_fd: i32 = syscall3(43, server_fd, 0);
97+
98+
if (client_fd < 0) {
99+
println("Error: Failed to accept connection.");
100+
continue;
101+
}
102+
103+
println("Client connected! fd: {}", client_fd);
104+
105+
var response: str = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nWelcome to the Wave HTTP Server!";
106+
107+
syscall4(1, client_fd, response, 82);
108+
109+
_socket_close(client_fd);
110+
println("Client disconnected.");
111+
}
112+
}
113+
114+
115+
fun main() {
116+
println("--- Wave HTTP Server Application ---");
117+
118+
var server_instance: i32 = new_server("0.0.0.0", 8080)
119+
.listen(10);
120+
121+
if (server_instance >= 0) {
122+
server_instance.start();
123+
} else {
124+
println("Server failed to start.");
125+
}
126+
}

0 commit comments

Comments
 (0)