From 83c3786de56afb81600b59ddec81ab823479fc72 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Wed, 12 Nov 2025 08:45:44 +0545 Subject: [PATCH 01/50] [+] init --- .gitignore | 1 + Cargo.toml | 6 ++++++ src/main.rs | 3 +++ 3 files changed, 10 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0f54a9b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "lsp85" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 23fbf85b4715f0a22ac7f850b9bd6aeb91ff5a18 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Thu, 20 Nov 2025 19:12:40 +0545 Subject: [PATCH 02/50] setup: added probable grammar --- .gitignore | 1 + Cargo.toml | 2 ++ grammar.txt | 21 +++++++++++++++++ src/frontend/lexer.rs | 52 ++++++++++++++++++++++++++++++++++++++++++ src/frontend/mod.rs | 3 +++ src/frontend/parser.rs | 0 src/frontend/token.rs | 28 +++++++++++++++++++++++ src/main.rs | 8 ++++++- src/server/mod.rs | 0 9 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 grammar.txt create mode 100644 src/frontend/lexer.rs create mode 100644 src/frontend/mod.rs create mode 100644 src/frontend/parser.rs create mode 100644 src/frontend/token.rs create mode 100644 src/server/mod.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..96ef6c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 0f54a9b..d25331d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,5 @@ version = "0.1.0" edition = "2024" [dependencies] +lsp-server = "0.7.9" +lsp-types = "0.97.0" diff --git a/grammar.txt b/grammar.txt new file mode 100644 index 0000000..38b3294 --- /dev/null +++ b/grammar.txt @@ -0,0 +1,21 @@ + +OPCODE : ADD + |... + +REGISTER : A + | B + | C + | D + | E + | H + | L + | SP + | PSW + + : OPCODE + : REGISTER | NUM_LITERAL | e + : , REGISTER | , NUM_LITERAL | e + +ADD A B + +ADD REGISTER REGISTER diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs new file mode 100644 index 0000000..8bad0d8 --- /dev/null +++ b/src/frontend/lexer.rs @@ -0,0 +1,52 @@ +use crate::frontend::token::{TokenType,Token}; +#[derive(Debug)] +struct Location{ + row: i64, + col: i64, +} +#[derive(Debug)] +pub struct Lexer{ + pub source: String, // source string + pub ch : char, // current literal + pub curr_position: usize, // current position + pub read_position: usize, // next position + // + // + pub location: Location, // current location +} + +impl Lexer{ + pub fn new(source: String)->Self{ + Self{ + source:source.clone(), + ch: source.chars().nth(0).expect("source of size <1?"), + curr_position: 0, + read_position: 1, + location:Location{row: 0,col: 0}, + } + } +} + +impl Lexer{ + pub fn next(&mut self){ + println!("{:?}",self); + self.consume(); + println!("{:?}",self); + } + pub fn consume(&mut self){ + if self.read_position >= self.source.len(){ + self.ch = '\0'; + }else{ + self.ch = self.source.chars().nth(self.read_position).unwrap_or(' '); + } + self.curr_position = self.read_position; + self.read_position = self.curr_position + 1; + + self.location.col += 1; + self.location.row = 0; + } + pub fn read_identifier(&mut self){ + + } +} + diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs new file mode 100644 index 0000000..b415544 --- /dev/null +++ b/src/frontend/mod.rs @@ -0,0 +1,3 @@ +pub mod parser; +pub mod lexer; +pub mod token; diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/frontend/token.rs b/src/frontend/token.rs new file mode 100644 index 0000000..ee3f11f --- /dev/null +++ b/src/frontend/token.rs @@ -0,0 +1,28 @@ +#[derive(Debug)] +pub struct Token { + tok_literal: String, + tok_type: TokenType, +} + +impl Token{ + pub fn new(tok_literal: String,tok_type: TokenType)->Self{ + Self{ + tok_literal, + tok_type, + } + } +} + +// ADD A,B +// +// INSTRUCTION +// OPERATION REGISTER COMMA_DELIM REGISTER +// +#[derive(Debug)] +pub enum TokenType{ + OPERATION, + IMM_VALUE, + REGISTER, + COMMA_DELIM, + EOF, +} diff --git a/src/main.rs b/src/main.rs index e7a11a9..b04bc37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,9 @@ +mod frontend; + +use frontend::lexer::{Lexer}; +use frontend::token::{Token,TokenType}; + fn main() { - println!("Hello, world!"); + let mut l = Lexer::new(String::from("Hello, world!\n")); + println!("{:?}",l.next()); } diff --git a/src/server/mod.rs b/src/server/mod.rs new file mode 100644 index 0000000..e69de29 From 6e3f5fcf3b2ce5600441d2c1818f42527009538c Mon Sep 17 00:00:00 2001 From: shri-acha Date: Thu, 20 Nov 2025 19:14:27 +0545 Subject: [PATCH 03/50] chore: cleaup --- src/frontend/lexer.rs | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 8bad0d8..3535810 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -1,52 +1,16 @@ use crate::frontend::token::{TokenType,Token}; + #[derive(Debug)] struct Location{ row: i64, col: i64, } + #[derive(Debug)] pub struct Lexer{ pub source: String, // source string pub ch : char, // current literal pub curr_position: usize, // current position pub read_position: usize, // next position - // - // pub location: Location, // current location } - -impl Lexer{ - pub fn new(source: String)->Self{ - Self{ - source:source.clone(), - ch: source.chars().nth(0).expect("source of size <1?"), - curr_position: 0, - read_position: 1, - location:Location{row: 0,col: 0}, - } - } -} - -impl Lexer{ - pub fn next(&mut self){ - println!("{:?}",self); - self.consume(); - println!("{:?}",self); - } - pub fn consume(&mut self){ - if self.read_position >= self.source.len(){ - self.ch = '\0'; - }else{ - self.ch = self.source.chars().nth(self.read_position).unwrap_or(' '); - } - self.curr_position = self.read_position; - self.read_position = self.curr_position + 1; - - self.location.col += 1; - self.location.row = 0; - } - pub fn read_identifier(&mut self){ - - } -} - From bbd154f38130c896543cf8ffcd45c45e334f7ba6 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Thu, 20 Nov 2025 20:17:10 +0545 Subject: [PATCH 04/50] feat: added lexing --- src/frontend/lexer.rs | 53 ++++++++++++++++++++++++++++++++++++++----- src/frontend/token.rs | 1 + src/main.rs | 5 +++- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 8bad0d8..65b2c46 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -28,10 +28,25 @@ impl Lexer{ } impl Lexer{ - pub fn next(&mut self){ - println!("{:?}",self); - self.consume(); - println!("{:?}",self); + pub fn next(&mut self)->Token{ + match self.ch { + c if self.ch.is_alphabetic() =>{ + // identifier + return self.read_identifier(); + } + ',' =>{ + self.consume(); + return Token::new(String::from(','),TokenType::COMMA_DELIM); + } + ' '=>{ + self.consume(); + return self.next(); + } + _=>{ + self.consume(); + return Token::new(String::from('\0'),TokenType::ILLEGAL); + } + } } pub fn consume(&mut self){ if self.read_position >= self.source.len(){ @@ -45,8 +60,34 @@ impl Lexer{ self.location.col += 1; self.location.row = 0; } - pub fn read_identifier(&mut self){ - + pub fn read_identifier(&mut self)->Token{ + let mut identifier_buf = String::from(""); + while self.ch.is_alphabetic(){ + identifier_buf += &self.ch.to_string(); + self.consume(); + } + return Token::new(identifier_buf.clone(),get_identifier_token(&identifier_buf)); + } +} +fn get_identifier_token(identifier_lit: &String)->TokenType{ + match identifier_lit.as_str(){ + "ADD" => { + return TokenType::OPERATION; + } + "A" + |"B" + |"C" + |"D" + |"E" + |"PSW" + |"H" + |"L" + =>{ + return TokenType::REGISTER; + } + _=>{ + return TokenType::ILLEGAL; + } } } diff --git a/src/frontend/token.rs b/src/frontend/token.rs index ee3f11f..0d11e90 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -25,4 +25,5 @@ pub enum TokenType{ REGISTER, COMMA_DELIM, EOF, + ILLEGAL, } diff --git a/src/main.rs b/src/main.rs index b04bc37..7b7ca3c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,9 @@ use frontend::lexer::{Lexer}; use frontend::token::{Token,TokenType}; fn main() { - let mut l = Lexer::new(String::from("Hello, world!\n")); + let mut l = Lexer::new(String::from("ADD A,B\n")); + println!("{:?}",l.next()); + println!("{:?}",l.next()); + println!("{:?}",l.next()); println!("{:?}",l.next()); } From e081d36d4811fa73ff4e67c0c1f9cc61d1c0a9cd Mon Sep 17 00:00:00 2001 From: shri-acha Date: Thu, 20 Nov 2025 20:39:03 +0545 Subject: [PATCH 05/50] feat: added broken lexing --- src/frontend/lexer.rs | 24 +++++++++++++++++++++--- src/frontend/token.rs | 1 + src/main.rs | 8 +++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 65b2c46..ec243ee 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -33,19 +33,29 @@ impl Lexer{ c if self.ch.is_alphabetic() =>{ // identifier return self.read_identifier(); + }, + c if self.ch.is_numeric() =>{ + return self.read_immediate(); } ',' =>{ self.consume(); return Token::new(String::from(','),TokenType::COMMA_DELIM); - } + }, ' '=>{ self.consume(); return self.next(); - } + }, + '\n'=>{ + self.consume(); + return Token::new(String::from('\0'),TokenType::EOL); + }, + '\0'=>{ + return Token::new(String::from('\0'),TokenType::EOF); + }, _=>{ self.consume(); return Token::new(String::from('\0'),TokenType::ILLEGAL); - } + }, } } pub fn consume(&mut self){ @@ -68,6 +78,14 @@ impl Lexer{ } return Token::new(identifier_buf.clone(),get_identifier_token(&identifier_buf)); } + pub fn read_immediate(&mut self)->Token{ + let mut immediate_buf = String::from(""); + while self.ch.is_numeric(){ + immediate_buf += &self.ch.to_string(); + self.consume(); + } + return Token::new(immediate_buf.clone(),TokenType::IMM_VALUE); + } } fn get_identifier_token(identifier_lit: &String)->TokenType{ match identifier_lit.as_str(){ diff --git a/src/frontend/token.rs b/src/frontend/token.rs index 0d11e90..b712612 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -24,6 +24,7 @@ pub enum TokenType{ IMM_VALUE, REGISTER, COMMA_DELIM, + EOL, EOF, ILLEGAL, } diff --git a/src/main.rs b/src/main.rs index 7b7ca3c..319cee2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,13 @@ use frontend::lexer::{Lexer}; use frontend::token::{Token,TokenType}; fn main() { - let mut l = Lexer::new(String::from("ADD A,B\n")); + let mut l = Lexer::new(String::from("ADD A,50\nADD B,D")); + println!("{:?}",l.next()); + println!("{:?}",l.next()); + println!("{:?}",l.next()); + println!("{:?}",l.next()); + println!("{:?}",l.next()); + println!("{:?}",l.next()); println!("{:?}",l.next()); println!("{:?}",l.next()); println!("{:?}",l.next()); From 5a529f1aaf76ef72fba93f767fb59d3c8cf27d4b Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 21 Nov 2025 08:09:54 +0545 Subject: [PATCH 06/50] refactor: refactored lexer as iterator --- src/frontend/lexer.rs | 19 +++++++++++-------- src/frontend/mod.rs | 1 + src/frontend/utils/files.rs | 17 +++++++++++++++++ src/frontend/utils/mod.rs | 1 + src/main.rs | 21 +++++++++------------ src/test_value.asm | 2 ++ 6 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 src/frontend/utils/files.rs create mode 100644 src/frontend/utils/mod.rs create mode 100644 src/test_value.asm diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index ec243ee..57a9b9e 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -27,19 +27,20 @@ impl Lexer{ } } -impl Lexer{ - pub fn next(&mut self)->Token{ +impl Iterator for Lexer{ + type Item = Token; + fn next(&mut self)->Option{ match self.ch { c if self.ch.is_alphabetic() =>{ // identifier - return self.read_identifier(); + return Some(self.read_identifier()); }, c if self.ch.is_numeric() =>{ - return self.read_immediate(); + return Some(self.read_immediate()); } ',' =>{ self.consume(); - return Token::new(String::from(','),TokenType::COMMA_DELIM); + return Some(Token::new(String::from(','),TokenType::COMMA_DELIM)); }, ' '=>{ self.consume(); @@ -47,17 +48,19 @@ impl Lexer{ }, '\n'=>{ self.consume(); - return Token::new(String::from('\0'),TokenType::EOL); + return Some(Token::new(String::from('\0'),TokenType::EOL)); }, '\0'=>{ - return Token::new(String::from('\0'),TokenType::EOF); + return Some(Token::new(String::from('\0'),TokenType::EOF)); }, _=>{ self.consume(); - return Token::new(String::from('\0'),TokenType::ILLEGAL); + return Some(Token::new(String::from('\0'),TokenType::ILLEGAL)); }, } } +} +impl Lexer { pub fn consume(&mut self){ if self.read_position >= self.source.len(){ self.ch = '\0'; diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index b415544..4485c4b 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -1,3 +1,4 @@ pub mod parser; pub mod lexer; pub mod token; +pub mod utils; diff --git a/src/frontend/utils/files.rs b/src/frontend/utils/files.rs new file mode 100644 index 0000000..8c7eeec --- /dev/null +++ b/src/frontend/utils/files.rs @@ -0,0 +1,17 @@ +use std::fs::File; +use std::io::Read; + +pub fn get_raw_source(f_name: &'static str)->Option{ + let mut f_contents = String::from(""); + let mut f = File::open(f_name); + if let Ok(mut f) = f { + if let Ok(_) = f.read_to_string(&mut f_contents){ + return Some(f_contents); + } + else { + return None; + } + }else { + return None; + } +} diff --git a/src/frontend/utils/mod.rs b/src/frontend/utils/mod.rs new file mode 100644 index 0000000..d3ab969 --- /dev/null +++ b/src/frontend/utils/mod.rs @@ -0,0 +1 @@ +pub mod files; diff --git a/src/main.rs b/src/main.rs index 319cee2..18c5c3f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,17 +2,14 @@ mod frontend; use frontend::lexer::{Lexer}; use frontend::token::{Token,TokenType}; +use frontend::utils::files::get_raw_source; -fn main() { - let mut l = Lexer::new(String::from("ADD A,50\nADD B,D")); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); +fn main(){ + if let Some(source) = get_raw_source("test_value.asm"){ + let mut l = Lexer::new(source); + println!("{:?}",l.next()); + println!("{:?}",l.next()); + println!("{:?}",l.next()); + println!("{:?}",l.next()); + } } diff --git a/src/test_value.asm b/src/test_value.asm new file mode 100644 index 0000000..2ce6d96 --- /dev/null +++ b/src/test_value.asm @@ -0,0 +1,2 @@ +ADD A,B +ADD B,C From c6ca3087493b5e3c4e606c69ef9c279e10781272 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 21 Nov 2025 08:52:28 +0545 Subject: [PATCH 07/50] feat: added location and character offset data on tokens --- src/frontend/lexer.rs | 29 +++++++++++++---------------- src/frontend/parser.rs | 14 ++++++++++++++ src/frontend/token.rs | 24 +++++++++++++++++++++--- src/main.rs | 9 +++++---- 4 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 57a9b9e..1c678a6 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -1,17 +1,13 @@ -use crate::frontend::token::{TokenType,Token}; -#[derive(Debug)] -struct Location{ - row: i64, - col: i64, -} +use crate::frontend::token::{TokenType,Token,Location}; + #[derive(Debug)] pub struct Lexer{ pub source: String, // source string pub ch : char, // current literal pub curr_position: usize, // current position pub read_position: usize, // next position - // - // + // + // pub location: Location, // current location } @@ -40,22 +36,25 @@ impl Iterator for Lexer{ } ',' =>{ self.consume(); - return Some(Token::new(String::from(','),TokenType::COMMA_DELIM)); + return Some(Token::new(String::from(','),TokenType::COMMA_DELIM,self.location,1)); }, ' '=>{ self.consume(); return self.next(); }, '\n'=>{ + + self.location.col = 0; + self.location.row += 1; self.consume(); - return Some(Token::new(String::from('\0'),TokenType::EOL)); + return Some(Token::new(String::from('\n'),TokenType::EOL,self.location,1)); }, '\0'=>{ - return Some(Token::new(String::from('\0'),TokenType::EOF)); + return None; }, _=>{ self.consume(); - return Some(Token::new(String::from('\0'),TokenType::ILLEGAL)); + return Some(Token::new(String::from('\0'),TokenType::ILLEGAL,self.location,1)); }, } } @@ -69,9 +68,7 @@ impl Lexer { } self.curr_position = self.read_position; self.read_position = self.curr_position + 1; - self.location.col += 1; - self.location.row = 0; } pub fn read_identifier(&mut self)->Token{ let mut identifier_buf = String::from(""); @@ -79,7 +76,7 @@ impl Lexer { identifier_buf += &self.ch.to_string(); self.consume(); } - return Token::new(identifier_buf.clone(),get_identifier_token(&identifier_buf)); + return Token::new(identifier_buf.clone(),get_identifier_token(&identifier_buf),self.location,identifier_buf.len()); } pub fn read_immediate(&mut self)->Token{ let mut immediate_buf = String::from(""); @@ -87,7 +84,7 @@ impl Lexer { immediate_buf += &self.ch.to_string(); self.consume(); } - return Token::new(immediate_buf.clone(),TokenType::IMM_VALUE); + return Token::new(immediate_buf.clone(),TokenType::IMM_VALUE,self.location,immediate_buf.len()); } } fn get_identifier_token(identifier_lit: &String)->TokenType{ diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index e69de29..cbd5c49 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -0,0 +1,14 @@ +use crate::frontend::token::{Token,TokenType}; +use std::iter::{Peekable, }; +use std::vec::IntoIter; + +struct Parser{ + tok_stream: Peekable>, +} +impl Parser{ + pub fn new(tok_stream: IntoIter)->Self{ + Self{ + tok_stream:tok_stream.peekable() + } + } +} diff --git a/src/frontend/token.rs b/src/frontend/token.rs index b712612..c0c6f2e 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -1,14 +1,32 @@ +#[derive(Debug,Copy,Clone)] +pub struct Location{ + pub row: i32, + pub col: i32, +} +impl Location{ + pub fn new(row: i32,col: i32)->Self{ + Self{ + row, + col, + } + } +} + #[derive(Debug)] pub struct Token { - tok_literal: String, - tok_type: TokenType, + pub tok_literal: String, + pub tok_type: TokenType, + pub location: Location, + pub offset: usize, // -ve char offset } impl Token{ - pub fn new(tok_literal: String,tok_type: TokenType)->Self{ + pub fn new(tok_literal: String,tok_type: TokenType,location: Location,offset: usize)->Self{ Self{ tok_literal, tok_type, + location, + offset, } } } diff --git a/src/main.rs b/src/main.rs index 18c5c3f..d8781fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,10 @@ use frontend::utils::files::get_raw_source; fn main(){ if let Some(source) = get_raw_source("test_value.asm"){ let mut l = Lexer::new(source); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); - println!("{:?}",l.next()); + let mut tokns_buf : Vec = vec![]; + for tok in l { + tokns_buf.push(tok); + } + println!("{:?}",tokns_buf); } } From dfc740a5155673315ec9214193e8bcb000dd6d47 Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Fri, 21 Nov 2025 15:16:33 +0545 Subject: [PATCH 08/50] chore: run cargo fmt --- src/frontend/lexer.rs | 124 ++++++++++++++++++++++++------------------ src/frontend/token.rs | 28 +++++----- src/main.rs | 12 ++-- 3 files changed, 91 insertions(+), 73 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 846f0ae..d932ccb 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -1,106 +1,122 @@ -use crate::frontend::token::{TokenType,Token,Location}; +use crate::frontend::token::{Location, Token, TokenType}; #[derive(Debug)] -pub struct Lexer{ - pub source: String, // source string - pub ch : char, // current literal - pub curr_position: usize, // current position - pub read_position: usize, // next position - pub location: Location, // current location +pub struct Lexer { + pub source: String, // source string + pub ch: char, // current literal + pub curr_position: usize, // current position + pub read_position: usize, // next position + pub location: Location, // current location } -impl Lexer{ - pub fn new(source: String)->Self{ - Self{ - source:source.clone(), +impl Lexer { + pub fn new(source: String) -> Self { + Self { + source: source.clone(), ch: source.chars().nth(0).expect("source of size <1?"), curr_position: 0, read_position: 1, - location:Location{row: 0,col: 0}, + location: Location { row: 0, col: 0 }, } } } -impl Iterator for Lexer{ - type Item = Token; - fn next(&mut self)->Option{ +impl Iterator for Lexer { + type Item = Token; + fn next(&mut self) -> Option { match self.ch { - c if self.ch.is_alphabetic() =>{ + c if self.ch.is_alphabetic() => { // identifier return Some(self.read_identifier()); - }, - c if self.ch.is_numeric() =>{ + } + c if self.ch.is_numeric() => { return Some(self.read_immediate()); } - ',' =>{ + ',' => { self.consume(); - return Some(Token::new(String::from(','),TokenType::COMMA_DELIM,self.location,1)); - }, - ' '=>{ + return Some(Token::new( + String::from(','), + TokenType::COMMA_DELIM, + self.location, + 1, + )); + } + ' ' => { self.consume(); return self.next(); - }, - '\n'=>{ - + } + '\n' => { self.location.col = 0; self.location.row += 1; self.consume(); - return Some(Token::new(String::from('\n'),TokenType::EOL,self.location,1)); - }, - '\0'=>{ + return Some(Token::new( + String::from('\n'), + TokenType::EOL, + self.location, + 1, + )); + } + '\0' => { return None; - }, - _=>{ + } + _ => { self.consume(); - return Some(Token::new(String::from('\0'),TokenType::ILLEGAL,self.location,1)); - }, + return Some(Token::new( + String::from('\0'), + TokenType::ILLEGAL, + self.location, + 1, + )); + } } } } impl Lexer { - pub fn consume(&mut self){ - if self.read_position >= self.source.len(){ + pub fn consume(&mut self) { + if self.read_position >= self.source.len() { self.ch = '\0'; - }else{ + } else { self.ch = self.source.chars().nth(self.read_position).unwrap_or(' '); } self.curr_position = self.read_position; self.read_position = self.curr_position + 1; self.location.col += 1; } - pub fn read_identifier(&mut self)->Token{ + pub fn read_identifier(&mut self) -> Token { let mut identifier_buf = String::from(""); - while self.ch.is_alphabetic(){ + while self.ch.is_alphabetic() { identifier_buf += &self.ch.to_string(); self.consume(); } - return Token::new(identifier_buf.clone(),get_identifier_token(&identifier_buf),self.location,identifier_buf.len()); + return Token::new( + identifier_buf.clone(), + get_identifier_token(&identifier_buf), + self.location, + identifier_buf.len(), + ); } - pub fn read_immediate(&mut self)->Token{ + pub fn read_immediate(&mut self) -> Token { let mut immediate_buf = String::from(""); - while self.ch.is_numeric(){ + while self.ch.is_numeric() { immediate_buf += &self.ch.to_string(); self.consume(); } - return Token::new(immediate_buf.clone(),TokenType::IMM_VALUE,self.location,immediate_buf.len()); + return Token::new( + immediate_buf.clone(), + TokenType::IMM_VALUE, + self.location, + immediate_buf.len(), + ); } } -fn get_identifier_token(identifier_lit: &String)->TokenType{ - match identifier_lit.as_str(){ +fn get_identifier_token(identifier_lit: &String) -> TokenType { + match identifier_lit.as_str() { "ADD" => { - return TokenType::OPERATION; + return TokenType::OPERATION; } - "A" - |"B" - |"C" - |"D" - |"E" - |"PSW" - |"H" - |"L" - =>{ + "A" | "B" | "C" | "D" | "E" | "PSW" | "H" | "L" => { return TokenType::REGISTER; } - _=>{ + _ => { return TokenType::ILLEGAL; } } diff --git a/src/frontend/token.rs b/src/frontend/token.rs index c0c6f2e..09ce5bc 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -1,14 +1,11 @@ -#[derive(Debug,Copy,Clone)] -pub struct Location{ +#[derive(Debug, Copy, Clone)] +pub struct Location { pub row: i32, pub col: i32, } -impl Location{ - pub fn new(row: i32,col: i32)->Self{ - Self{ - row, - col, - } +impl Location { + pub fn new(row: i32, col: i32) -> Self { + Self { row, col } } } @@ -17,12 +14,17 @@ pub struct Token { pub tok_literal: String, pub tok_type: TokenType, pub location: Location, - pub offset: usize, // -ve char offset + pub offset: usize, // -ve char offset } -impl Token{ - pub fn new(tok_literal: String,tok_type: TokenType,location: Location,offset: usize)->Self{ - Self{ +impl Token { + pub fn new( + tok_literal: String, + tok_type: TokenType, + location: Location, + offset: usize, + ) -> Self { + Self { tok_literal, tok_type, location, @@ -37,7 +39,7 @@ impl Token{ // OPERATION REGISTER COMMA_DELIM REGISTER // #[derive(Debug)] -pub enum TokenType{ +pub enum TokenType { OPERATION, IMM_VALUE, REGISTER, diff --git a/src/main.rs b/src/main.rs index d8781fd..a18c03a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,16 @@ mod frontend; -use frontend::lexer::{Lexer}; -use frontend::token::{Token,TokenType}; +use frontend::lexer::Lexer; +use frontend::token::{Token, TokenType}; use frontend::utils::files::get_raw_source; -fn main(){ - if let Some(source) = get_raw_source("test_value.asm"){ +fn main() { + if let Some(source) = get_raw_source("test_value.asm") { let mut l = Lexer::new(source); - let mut tokns_buf : Vec = vec![]; + let mut tokns_buf: Vec = vec![]; for tok in l { tokns_buf.push(tok); } - println!("{:?}",tokns_buf); + println!("{:?}", tokns_buf); } } From 01cee6096e6336cafd6865863dc9f39fabd6bd3c Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Fri, 21 Nov 2025 15:17:08 +0545 Subject: [PATCH 09/50] REFACTOR: removed unnecessary clone --- src/frontend/lexer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index d932ccb..eef63d6 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -11,11 +11,11 @@ pub struct Lexer { impl Lexer { pub fn new(source: String) -> Self { Self { - source: source.clone(), ch: source.chars().nth(0).expect("source of size <1?"), curr_position: 0, read_position: 1, location: Location { row: 0, col: 0 }, + source: source, } } } From c6d4aff3bf3e441e262089d60d1df28af72ae2b9 Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Fri, 21 Nov 2025 15:20:46 +0545 Subject: [PATCH 10/50] Feat: Add RP support to lexer --- src/frontend/lexer.rs | 6 +++++- src/frontend/token.rs | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index eef63d6..ac364c8 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -110,12 +110,16 @@ impl Lexer { } fn get_identifier_token(identifier_lit: &String) -> TokenType { match identifier_lit.as_str() { - "ADD" => { + "ADD" | "SUB" | "MOV" | "MVI" | "LXI" | "PUSH" | "POP" | "INR" | "DCR" | "DAD" | "LDAX" + | "STAX" => { return TokenType::OPERATION; } "A" | "B" | "C" | "D" | "E" | "PSW" | "H" | "L" => { return TokenType::REGISTER; } + "BC" | "DE" | "HL" | "SP" => { + return TokenType::REGISTER_PAIR; + } _ => { return TokenType::ILLEGAL; } diff --git a/src/frontend/token.rs b/src/frontend/token.rs index 09ce5bc..7cefe9c 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -43,6 +43,7 @@ pub enum TokenType { OPERATION, IMM_VALUE, REGISTER, + REGISTER_PAIR, COMMA_DELIM, EOL, EOF, From e9b7463a85fff4e5eae305c18bfc216b53052039 Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Fri, 21 Nov 2025 15:31:50 +0545 Subject: [PATCH 11/50] Feat: added hex support with H suffix --- src/frontend/lexer.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index ac364c8..474d60a 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -96,7 +96,15 @@ impl Lexer { } pub fn read_immediate(&mut self) -> Token { let mut immediate_buf = String::from(""); - while self.ch.is_numeric() { + + //Support for hex digits + while self.ch.is_ascii_hexdigit() { + immediate_buf += &self.ch.to_string(); + self.consume(); + } + + //H suffix handling Eg: 123AH + if self.ch == 'H' { immediate_buf += &self.ch.to_string(); self.consume(); } From ea58a0faea687b11741b07a88a57df14b3e448b4 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 21 Nov 2025 17:01:45 +0545 Subject: [PATCH 12/50] feat: added test for lexer --- src/frontend/lexer.rs | 35 ++++++++++++++++++++++++++++++++--- src/frontend/token.rs | 6 +++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 474d60a..4611b0a 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -1,4 +1,7 @@ use crate::frontend::token::{Location, Token, TokenType}; + + + #[derive(Debug)] pub struct Lexer { pub source: String, // source string @@ -45,15 +48,17 @@ impl Iterator for Lexer { return self.next(); } '\n' => { - self.location.col = 0; - self.location.row += 1; self.consume(); - return Some(Token::new( + let buf_token = Some(Token::new( String::from('\n'), TokenType::EOL, self.location, 1, )); + self.location.col = 0; + self.location.row += 1; + + return buf_token; } '\0' => { return None; @@ -133,3 +138,27 @@ fn get_identifier_token(identifier_lit: &String) -> TokenType { } } } + +#[cfg(test)] +mod tests{ + + use crate::frontend::token::{Location, Token, TokenType}; + use super::Lexer; + #[test] + fn lexer_test_case(){ + let source = String::from("ADD A,B\n"); + let mut l = Lexer::new(source); + let mut tokens: Vec = vec![]; + for token in l { tokens.push(token); } + + assert_eq!( + vec![ + Token::new("ADD".to_string(),TokenType::OPERATION,Location::new(0,3),3), + Token::new("A".to_string(),TokenType::REGISTER,Location::new(0,5),1), + Token::new(",".to_string(),TokenType::COMMA_DELIM,Location::new(0,6),1), + Token::new("B".to_string(),TokenType::REGISTER,Location::new(0,7),1), + Token::new("\n".to_string(),TokenType::EOL,Location::new(0,8),1) + ] + ,tokens); + } +} diff --git a/src/frontend/token.rs b/src/frontend/token.rs index 7cefe9c..d27f96c 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone,PartialEq)] pub struct Location { pub row: i32, pub col: i32, @@ -9,7 +9,7 @@ impl Location { } } -#[derive(Debug)] +#[derive(Debug,PartialEq)] pub struct Token { pub tok_literal: String, pub tok_type: TokenType, @@ -38,7 +38,7 @@ impl Token { // INSTRUCTION // OPERATION REGISTER COMMA_DELIM REGISTER // -#[derive(Debug)] +#[derive(Debug,PartialEq)] pub enum TokenType { OPERATION, IMM_VALUE, From 6cdeeea3e78740495bdd0a2dc86f500e0f2479a7 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 21 Nov 2025 17:04:57 +0545 Subject: [PATCH 13/50] chore: cargo fmt --- src/frontend/lexer.rs | 37 ++++++++++++++++++++++++------------- src/frontend/mod.rs | 2 +- src/frontend/parser.rs | 14 +++++++------- src/frontend/token.rs | 6 +++--- src/frontend/utils/files.rs | 9 ++++----- 5 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 4611b0a..2635a68 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -1,7 +1,5 @@ use crate::frontend::token::{Location, Token, TokenType}; - - #[derive(Debug)] pub struct Lexer { pub source: String, // source string @@ -140,25 +138,38 @@ fn get_identifier_token(identifier_lit: &String) -> TokenType { } #[cfg(test)] -mod tests{ +mod tests { - use crate::frontend::token::{Location, Token, TokenType}; use super::Lexer; + use crate::frontend::token::{Location, Token, TokenType}; #[test] - fn lexer_test_case(){ + fn lexer_test_case() { let source = String::from("ADD A,B\n"); let mut l = Lexer::new(source); let mut tokens: Vec = vec![]; - for token in l { tokens.push(token); } + for token in l { + tokens.push(token); + } assert_eq!( vec![ - Token::new("ADD".to_string(),TokenType::OPERATION,Location::new(0,3),3), - Token::new("A".to_string(),TokenType::REGISTER,Location::new(0,5),1), - Token::new(",".to_string(),TokenType::COMMA_DELIM,Location::new(0,6),1), - Token::new("B".to_string(),TokenType::REGISTER,Location::new(0,7),1), - Token::new("\n".to_string(),TokenType::EOL,Location::new(0,8),1) - ] - ,tokens); + Token::new( + "ADD".to_string(), + TokenType::OPERATION, + Location::new(0, 3), + 3 + ), + Token::new("A".to_string(), TokenType::REGISTER, Location::new(0, 5), 1), + Token::new( + ",".to_string(), + TokenType::COMMA_DELIM, + Location::new(0, 6), + 1 + ), + Token::new("B".to_string(), TokenType::REGISTER, Location::new(0, 7), 1), + Token::new("\n".to_string(), TokenType::EOL, Location::new(0, 8), 1) + ], + tokens + ); } } diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 4485c4b..306e9fa 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -1,4 +1,4 @@ -pub mod parser; pub mod lexer; +pub mod parser; pub mod token; pub mod utils; diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index cbd5c49..75d0219 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -1,14 +1,14 @@ -use crate::frontend::token::{Token,TokenType}; -use std::iter::{Peekable, }; +use crate::frontend::token::{Token, TokenType}; +use std::iter::Peekable; use std::vec::IntoIter; -struct Parser{ +struct Parser { tok_stream: Peekable>, } -impl Parser{ - pub fn new(tok_stream: IntoIter)->Self{ - Self{ - tok_stream:tok_stream.peekable() +impl Parser { + pub fn new(tok_stream: IntoIter) -> Self { + Self { + tok_stream: tok_stream.peekable(), } } } diff --git a/src/frontend/token.rs b/src/frontend/token.rs index d27f96c..2d6f2d0 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -1,4 +1,4 @@ -#[derive(Debug, Copy, Clone,PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub struct Location { pub row: i32, pub col: i32, @@ -9,7 +9,7 @@ impl Location { } } -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Token { pub tok_literal: String, pub tok_type: TokenType, @@ -38,7 +38,7 @@ impl Token { // INSTRUCTION // OPERATION REGISTER COMMA_DELIM REGISTER // -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub enum TokenType { OPERATION, IMM_VALUE, diff --git a/src/frontend/utils/files.rs b/src/frontend/utils/files.rs index 8c7eeec..9ced476 100644 --- a/src/frontend/utils/files.rs +++ b/src/frontend/utils/files.rs @@ -1,17 +1,16 @@ use std::fs::File; use std::io::Read; -pub fn get_raw_source(f_name: &'static str)->Option{ +pub fn get_raw_source(f_name: &'static str) -> Option { let mut f_contents = String::from(""); let mut f = File::open(f_name); if let Ok(mut f) = f { - if let Ok(_) = f.read_to_string(&mut f_contents){ + if let Ok(_) = f.read_to_string(&mut f_contents) { return Some(f_contents); - } - else { + } else { return None; } - }else { + } else { return None; } } From 07a466e4f0c2dbc17d8d2a06a99bd59c9b37038e Mon Sep 17 00:00:00 2001 From: shri-acha Date: Sat, 22 Nov 2025 09:08:43 +0545 Subject: [PATCH 14/50] feat: added buffered reading --- src/frontend/lexer.rs | 41 ++++++++++++++++++++++++++++++++----- src/frontend/utils/files.rs | 21 ++++++++----------- src/main.rs | 26 +++++++++++++++-------- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 2635a68..548fa52 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -143,8 +143,8 @@ mod tests { use super::Lexer; use crate::frontend::token::{Location, Token, TokenType}; #[test] - fn lexer_test_case() { - let source = String::from("ADD A,B\n"); + fn imm_test() { + let source = String::from("MVI A,05H\n"); let mut l = Lexer::new(source); let mut tokens: Vec = vec![]; for token in l { @@ -154,7 +154,7 @@ mod tests { assert_eq!( vec![ Token::new( - "ADD".to_string(), + "MVI".to_string(), TokenType::OPERATION, Location::new(0, 3), 3 @@ -166,8 +166,39 @@ mod tests { Location::new(0, 6), 1 ), - Token::new("B".to_string(), TokenType::REGISTER, Location::new(0, 7), 1), - Token::new("\n".to_string(), TokenType::EOL, Location::new(0, 8), 1) + Token::new("05H".to_string(), TokenType::IMM_VALUE, Location::new(0, 9), 3), + Token::new("\n".to_string(), TokenType::EOL, Location::new(0, 10), 1) + ], + tokens + ); + } + + #[test] + fn reg_pair() { + let source = String::from("MVI A,SP\n"); + let mut l = Lexer::new(source); + let mut tokens: Vec = vec![]; + for token in l { + tokens.push(token); + } + + assert_eq!( + vec![ + Token::new( + "MVI".to_string(), + TokenType::OPERATION, + Location::new(0, 3), + 3 + ), + Token::new("A".to_string(), TokenType::REGISTER, Location::new(0, 5), 1), + Token::new( + ",".to_string(), + TokenType::COMMA_DELIM, + Location::new(0, 6), + 1 + ), + Token::new("SP".to_string(), TokenType::REGISTER_PAIR, Location::new(0, 8), 2), + Token::new("\n".to_string(), TokenType::EOL, Location::new(0, 9), 1) ], tokens ); diff --git a/src/frontend/utils/files.rs b/src/frontend/utils/files.rs index 9ced476..3c0573e 100644 --- a/src/frontend/utils/files.rs +++ b/src/frontend/utils/files.rs @@ -1,16 +1,13 @@ use std::fs::File; use std::io::Read; +use std::io::BufReader; +use std::io::BufRead; +use std::iter::Enumerate; +use std::io::Lines; -pub fn get_raw_source(f_name: &'static str) -> Option { - let mut f_contents = String::from(""); - let mut f = File::open(f_name); - if let Ok(mut f) = f { - if let Ok(_) = f.read_to_string(&mut f_contents) { - return Some(f_contents); - } else { - return None; - } - } else { - return None; - } +pub fn get_source_buffer(f_name: &'static str) -> Option>>> { + let file = File::open(f_name).ok()?; + let buffer = BufReader::new(file); + let lines = buffer.lines().enumerate(); + return Some(lines); } diff --git a/src/main.rs b/src/main.rs index a18c03a..d8012ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,15 +2,25 @@ mod frontend; use frontend::lexer::Lexer; use frontend::token::{Token, TokenType}; -use frontend::utils::files::get_raw_source; +use frontend::utils::files::get_source_buffer; -fn main() { - if let Some(source) = get_raw_source("test_value.asm") { - let mut l = Lexer::new(source); - let mut tokns_buf: Vec = vec![]; - for tok in l { - tokns_buf.push(tok); +fn main() { + + if let Some(source) = get_source_buffer("test_value.asm") { + // buffered reading + for (_,read_buf) in source { + if let Ok(read_buf) = read_buf{ + + let mut l = Lexer::new(read_buf); + let mut tokns_buf: Vec = vec![]; + for tok in l { + tokns_buf.push(tok); + } + println!("{:?}", tokns_buf); + + }else { + println!("Error reading!"); + } } - println!("{:?}", tokns_buf); } } From 8906837062197caff1240901cfdc67e49ea14508 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Sat, 22 Nov 2025 09:36:25 +0545 Subject: [PATCH 15/50] fix: fixed broken row count and introduced parser structs --- src/frontend/lexer.rs | 24 ++++++++++++------------ src/frontend/parser.rs | 20 +++++++++++++++++++- src/frontend/token.rs | 10 +++++----- src/main.rs | 8 ++++++-- src/test_value.asm | 2 -- 5 files changed, 42 insertions(+), 22 deletions(-) delete mode 100644 src/test_value.asm diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 548fa52..04ab71f 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -10,12 +10,12 @@ pub struct Lexer { } impl Lexer { - pub fn new(source: String) -> Self { + pub fn new(source: String,line_no: usize) -> Self { Self { ch: source.chars().nth(0).expect("source of size <1?"), curr_position: 0, read_position: 1, - location: Location { row: 0, col: 0 }, + location: Location { row: line_no, col: 0 }, source: source, } } @@ -35,10 +35,10 @@ impl Iterator for Lexer { ',' => { self.consume(); return Some(Token::new( - String::from(','), + 1, TokenType::COMMA_DELIM, self.location, - 1, + String::from(','), )); } ' ' => { @@ -48,10 +48,10 @@ impl Iterator for Lexer { '\n' => { self.consume(); let buf_token = Some(Token::new( - String::from('\n'), + 1, TokenType::EOL, self.location, - 1, + String::from('\n'), )); self.location.col = 0; self.location.row += 1; @@ -64,10 +64,10 @@ impl Iterator for Lexer { _ => { self.consume(); return Some(Token::new( - String::from('\0'), + 1, TokenType::ILLEGAL, self.location, - 1, + String::from('\0'), )); } } @@ -91,10 +91,10 @@ impl Lexer { self.consume(); } return Token::new( - identifier_buf.clone(), + identifier_buf.len(), get_identifier_token(&identifier_buf), self.location, - identifier_buf.len(), + identifier_buf, ); } pub fn read_immediate(&mut self) -> Token { @@ -112,10 +112,10 @@ impl Lexer { self.consume(); } return Token::new( - immediate_buf.clone(), + immediate_buf.len(), TokenType::IMM_VALUE, self.location, - immediate_buf.len(), + immediate_buf, ); } } diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index 75d0219..3269d0a 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -2,7 +2,8 @@ use crate::frontend::token::{Token, TokenType}; use std::iter::Peekable; use std::vec::IntoIter; -struct Parser { +#[derive(Debug)] +pub struct Parser { tok_stream: Peekable>, } impl Parser { @@ -12,3 +13,20 @@ impl Parser { } } } + +pub struct Tree{ + l_child: Option, + r_child: Option, +} + +pub struct Node{ + val: Token, + branch: Box, +} + + +impl Parser{ + pub fn parse(){ + + } +} diff --git a/src/frontend/token.rs b/src/frontend/token.rs index 2d6f2d0..852b393 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -1,10 +1,10 @@ #[derive(Debug, Copy, Clone, PartialEq)] pub struct Location { - pub row: i32, - pub col: i32, + pub row: usize, + pub col: usize, } impl Location { - pub fn new(row: i32, col: i32) -> Self { + pub fn new(row: usize, col: usize) -> Self { Self { row, col } } } @@ -19,10 +19,10 @@ pub struct Token { impl Token { pub fn new( - tok_literal: String, + offset: usize, tok_type: TokenType, location: Location, - offset: usize, + tok_literal: String, ) -> Self { Self { tok_literal, diff --git a/src/main.rs b/src/main.rs index d8012ec..f86be17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod frontend; use frontend::lexer::Lexer; +use frontend::parser::Parser; use frontend::token::{Token, TokenType}; use frontend::utils::files::get_source_buffer; @@ -8,19 +9,22 @@ fn main() { if let Some(source) = get_source_buffer("test_value.asm") { // buffered reading - for (_,read_buf) in source { + for (line_no,read_buf) in source { if let Ok(read_buf) = read_buf{ - let mut l = Lexer::new(read_buf); + let mut l = Lexer::new(read_buf,line_no); let mut tokns_buf: Vec = vec![]; for tok in l { tokns_buf.push(tok); } println!("{:?}", tokns_buf); + let mut p = Parser::new(tokns_buf.into_iter()); + }else { println!("Error reading!"); } } } + } diff --git a/src/test_value.asm b/src/test_value.asm deleted file mode 100644 index 2ce6d96..0000000 --- a/src/test_value.asm +++ /dev/null @@ -1,2 +0,0 @@ -ADD A,B -ADD B,C From 716a5a4b22228299f57c8e109e1c4d51c87204ec Mon Sep 17 00:00:00 2001 From: shri-acha Date: Mon, 24 Nov 2025 08:39:10 +0545 Subject: [PATCH 16/50] refactor: removed register pairs(they don't exist until 8086) --- src/frontend/lexer.rs | 26 +++++++++++++------ src/frontend/parser.rs | 51 ++++++++++++++++++++++++++++++++----- src/frontend/token.rs | 1 - src/frontend/utils/files.rs | 6 ++--- src/main.rs | 14 ++++------ src/server/mod.rs | 1 + 6 files changed, 71 insertions(+), 28 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 04ab71f..87e1178 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -10,12 +10,15 @@ pub struct Lexer { } impl Lexer { - pub fn new(source: String,line_no: usize) -> Self { + pub fn new(source: String, line_no: usize) -> Self { Self { ch: source.chars().nth(0).expect("source of size <1?"), curr_position: 0, read_position: 1, - location: Location { row: line_no, col: 0 }, + location: Location { + row: line_no, + col: 0, + }, source: source, } } @@ -48,7 +51,7 @@ impl Iterator for Lexer { '\n' => { self.consume(); let buf_token = Some(Token::new( - 1, + 1, TokenType::EOL, self.location, String::from('\n'), @@ -128,9 +131,6 @@ fn get_identifier_token(identifier_lit: &String) -> TokenType { "A" | "B" | "C" | "D" | "E" | "PSW" | "H" | "L" => { return TokenType::REGISTER; } - "BC" | "DE" | "HL" | "SP" => { - return TokenType::REGISTER_PAIR; - } _ => { return TokenType::ILLEGAL; } @@ -166,7 +166,12 @@ mod tests { Location::new(0, 6), 1 ), - Token::new("05H".to_string(), TokenType::IMM_VALUE, Location::new(0, 9), 3), + Token::new( + "05H".to_string(), + TokenType::IMM_VALUE, + Location::new(0, 9), + 3 + ), Token::new("\n".to_string(), TokenType::EOL, Location::new(0, 10), 1) ], tokens @@ -197,7 +202,12 @@ mod tests { Location::new(0, 6), 1 ), - Token::new("SP".to_string(), TokenType::REGISTER_PAIR, Location::new(0, 8), 2), + Token::new( + "SP".to_string(), + TokenType::REGISTER_PAIR, + Location::new(0, 8), + 2 + ), Token::new("\n".to_string(), TokenType::EOL, Location::new(0, 9), 1) ], tokens diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index 3269d0a..d80fc7d 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -14,19 +14,56 @@ impl Parser { } } +#[derive(Debug,PartialEq)] pub struct Tree{ - l_child: Option, - r_child: Option, + pub l_child: Option, + pub r_child: Option, } -pub struct Node{ - val: Token, - branch: Box, +impl Tree { + pub fn default()->Self{ + Self{ + l_child:None, + r_child:None, + } + } + + pub fn new(l_child:Option,r_child: Option)->Self{ + Self{ + l_child, + r_child + } + } +} +#[derive(Debug,PartialEq)] +pub struct Node { + pub value: Token, + pub branch: Box } +impl Node { + pub fn new(tok_val: Token, branch: Box)->Self{ + Self{ + value: tok_val, + branch + } + } +} -impl Parser{ - pub fn parse(){ +impl Parser { + pub fn parse_expression(&mut self) { + if let Some(peeked_token) = self.tok_stream.peek(){ + match peeked_token { + Token{tok_type: TokenType::OPERATION,..}=>{ + self.parse_operation(); + }, + Token{tok_type: TokenType::REGISTER,..}=>{ + self.parse_register(); + }, + } + } + } + pub fn parse_operation(){ } } diff --git a/src/frontend/token.rs b/src/frontend/token.rs index 852b393..8fca455 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -43,7 +43,6 @@ pub enum TokenType { OPERATION, IMM_VALUE, REGISTER, - REGISTER_PAIR, COMMA_DELIM, EOL, EOF, diff --git a/src/frontend/utils/files.rs b/src/frontend/utils/files.rs index 3c0573e..3d7f2a8 100644 --- a/src/frontend/utils/files.rs +++ b/src/frontend/utils/files.rs @@ -1,9 +1,9 @@ use std::fs::File; -use std::io::Read; -use std::io::BufReader; use std::io::BufRead; -use std::iter::Enumerate; +use std::io::BufReader; use std::io::Lines; +use std::io::Read; +use std::iter::Enumerate; pub fn get_source_buffer(f_name: &'static str) -> Option>>> { let file = File::open(f_name).ok()?; diff --git a/src/main.rs b/src/main.rs index f86be17..f955f22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,14 +5,12 @@ use frontend::parser::Parser; use frontend::token::{Token, TokenType}; use frontend::utils::files::get_source_buffer; -fn main() { - +fn main() { if let Some(source) = get_source_buffer("test_value.asm") { // buffered reading - for (line_no,read_buf) in source { - if let Ok(read_buf) = read_buf{ - - let mut l = Lexer::new(read_buf,line_no); + for (line_no, read_buf) in source { + if let Ok(read_buf) = read_buf { + let mut l = Lexer::new(read_buf, line_no); let mut tokns_buf: Vec = vec![]; for tok in l { tokns_buf.push(tok); @@ -20,11 +18,9 @@ fn main() { println!("{:?}", tokns_buf); let mut p = Parser::new(tokns_buf.into_iter()); - - }else { + } else { println!("Error reading!"); } } } - } diff --git a/src/server/mod.rs b/src/server/mod.rs index e69de29..8b13789 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -0,0 +1 @@ + From f3a0f192631d171645f1855ba0598ed67f5544cf Mon Sep 17 00:00:00 2001 From: shri-acha Date: Mon, 24 Nov 2025 13:22:06 +0545 Subject: [PATCH 17/50] feat: finished implementation of the parser, wip for server --- src/frontend/lexer.rs | 58 ++++++++++++++++++---------------- src/frontend/parser.rs | 71 ++++++++++++++++++++++++++++++++++++++---- src/frontend/token.rs | 5 +-- src/main.rs | 11 +++++-- src/test_value.asm | 3 ++ 5 files changed, 111 insertions(+), 37 deletions(-) create mode 100644 src/test_value.asm diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 87e1178..6934cff 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -128,7 +128,7 @@ fn get_identifier_token(identifier_lit: &String) -> TokenType { | "STAX" => { return TokenType::OPERATION; } - "A" | "B" | "C" | "D" | "E" | "PSW" | "H" | "L" => { + "A" | "B" | "C" | "D" | "E" | "PSW" | "H" | "L" | "SP" => { return TokenType::REGISTER; } _ => { @@ -145,7 +145,7 @@ mod tests { #[test] fn imm_test() { let source = String::from("MVI A,05H\n"); - let mut l = Lexer::new(source); + let mut l = Lexer::new(source,0); let mut tokens: Vec = vec![]; for token in l { tokens.push(token); @@ -154,25 +154,30 @@ mod tests { assert_eq!( vec![ Token::new( - "MVI".to_string(), + 3, TokenType::OPERATION, Location::new(0, 3), - 3 - ), - Token::new("A".to_string(), TokenType::REGISTER, Location::new(0, 5), 1), + "MVI".to_string()), Token::new( - ",".to_string(), + 1, + TokenType::REGISTER, + Location::new(0, 5), + "A".to_string()), + Token::new( + 1, TokenType::COMMA_DELIM, Location::new(0, 6), - 1 - ), + ",".to_string()), Token::new( - "05H".to_string(), + 3, TokenType::IMM_VALUE, Location::new(0, 9), - 3 - ), - Token::new("\n".to_string(), TokenType::EOL, Location::new(0, 10), 1) + "05H".to_string()), + Token::new( + 1, + TokenType::EOL, + Location::new(0, 10), + "\n".to_string()) ], tokens ); @@ -181,7 +186,7 @@ mod tests { #[test] fn reg_pair() { let source = String::from("MVI A,SP\n"); - let mut l = Lexer::new(source); + let mut l = Lexer::new(source,0); let mut tokens: Vec = vec![]; for token in l { tokens.push(token); @@ -190,25 +195,26 @@ mod tests { assert_eq!( vec![ Token::new( - "MVI".to_string(), + 3, TokenType::OPERATION, Location::new(0, 3), - 3 - ), - Token::new("A".to_string(), TokenType::REGISTER, Location::new(0, 5), 1), + "MVI".to_string()), + Token::new( 1, TokenType::REGISTER, Location::new(0, 5), "A".to_string()), Token::new( - ",".to_string(), + 1, TokenType::COMMA_DELIM, Location::new(0, 6), - 1 - ), + ",".to_string()), Token::new( - "SP".to_string(), - TokenType::REGISTER_PAIR, + 2, + TokenType::REGISTER, Location::new(0, 8), - 2 - ), - Token::new("\n".to_string(), TokenType::EOL, Location::new(0, 9), 1) + "SP".to_string()), + Token::new( + 1, + TokenType::EOL, + Location::new(0, 9), + "\n".to_string()) ], tokens ); diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index d80fc7d..3df4ffc 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -41,7 +41,7 @@ pub struct Node { pub branch: Box } -impl Node { +impl Node{ pub fn new(tok_val: Token, branch: Box)->Self{ Self{ value: tok_val, @@ -51,19 +51,78 @@ impl Node { } impl Parser { - pub fn parse_expression(&mut self) { + pub fn parse_expression(&mut self)->Option{ + if let Some(peeked_token) = self.tok_stream.peek(){ + println!("parse_expression() called! {:?}",peeked_token); match peeked_token { Token{tok_type: TokenType::OPERATION,..}=>{ - self.parse_operation(); + return self.parse_operation(); }, - Token{tok_type: TokenType::REGISTER,..}=>{ - self.parse_register(); + Token{tok_type: TokenType::REGISTER, ..}=>{ + println!("unexpected placement of register!"); + return None; + } + Token{tok_type: TokenType::EOF, ..}=>{ + return None; + } + _ =>{ + self.tok_stream.next(); + return self.parse_expression(); + } + } + }else{ + return None; + } + } + pub fn parse_operation(&mut self)->Option{ + let mut l_child: Node; + if let Some(peeked_token) = self.tok_stream.peek(){ + l_child = Node::new(peeked_token.clone(),Box::new(Tree::default())); + }else{ + return None; + } + self.tok_stream.next(); + if let Some(peeked_token) = self.tok_stream.peek(){ + match peeked_token{ + Token{ tok_type: TokenType::REGISTER, .. }=>{ + l_child.branch.l_child = self.parse_operand(); + l_child.branch.r_child = self.parse_operand(); + return Some(l_child); }, + _=>{ + return Some(l_child); + } } + }else{ + return Some(l_child); } } - pub fn parse_operation(){ + pub fn parse_operand(&mut self)->Option{ + let mut l_child: Node; + if let Some(peeked_token) = self.tok_stream.peek(){ + match peeked_token{ + Token{tok_type: TokenType:: REGISTER, .. }=>{ + let token_buffer = peeked_token.clone(); + self.tok_stream.next(); + return Some(Node::new(token_buffer,Box::new(Tree::default()))); + }, + Token{tok_type: TokenType:: COMMA_DELIM, .. }=>{ + self.tok_stream.next(); + return self.parse_operand(); + }, + Token{tok_type: TokenType:: IMM_VALUE, .. }=>{ + let token_buffer = peeked_token.clone(); + self.tok_stream.next(); + return Some(Node::new(token_buffer,Box::new(Tree::default()))); + }, + _ =>{ + return None; + } + } + }else{ + return None; + } } } diff --git a/src/frontend/token.rs b/src/frontend/token.rs index 8fca455..cada4bb 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -9,7 +9,7 @@ impl Location { } } -#[derive(Debug, PartialEq)] +#[derive(Debug,Clone,PartialEq)] pub struct Token { pub tok_literal: String, pub tok_type: TokenType, @@ -38,12 +38,13 @@ impl Token { // INSTRUCTION // OPERATION REGISTER COMMA_DELIM REGISTER // -#[derive(Debug, PartialEq)] +#[derive(Debug,Copy,Clone,PartialEq)] pub enum TokenType { OPERATION, IMM_VALUE, REGISTER, COMMA_DELIM, + BOL, EOL, EOF, ILLEGAL, diff --git a/src/main.rs b/src/main.rs index f955f22..b2e9b7a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,31 @@ mod frontend; use frontend::lexer::Lexer; -use frontend::parser::Parser; -use frontend::token::{Token, TokenType}; +use frontend::parser::{Parser,Node}; +use frontend::token::{Token, TokenType,Location}; use frontend::utils::files::get_source_buffer; fn main() { if let Some(source) = get_source_buffer("test_value.asm") { // buffered reading + let mut ast_list: Vec> = vec![]; for (line_no, read_buf) in source { if let Ok(read_buf) = read_buf { let mut l = Lexer::new(read_buf, line_no); let mut tokns_buf: Vec = vec![]; + tokns_buf.push(Token::new(0,TokenType::BOL,Location::new(0,0),String::from("BOL"))); + for tok in l { tokns_buf.push(tok); } - println!("{:?}", tokns_buf); + // println!("{:?}", tokns_buf); let mut p = Parser::new(tokns_buf.into_iter()); + ast_list.push(p.parse_expression()); } else { println!("Error reading!"); } + println!("{:?}",ast_list); } } } diff --git a/src/test_value.asm b/src/test_value.asm new file mode 100644 index 0000000..87833e6 --- /dev/null +++ b/src/test_value.asm @@ -0,0 +1,3 @@ +MVI SP,0001H +MOV B,A +MVI B,00H From bb184b92f82c3caa8ca5c555d01d455ae0d2379c Mon Sep 17 00:00:00 2001 From: shri-acha Date: Tue, 25 Nov 2025 10:49:04 +0545 Subject: [PATCH 18/50] feat: init server capability, wip add message dispatch loop --- src/main.rs | 84 ++++++++++++++++++++++++++++++++--------------- src/server/mod.rs | 1 - 2 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/main.rs b/src/main.rs index b2e9b7a..5b7438f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,61 @@ mod frontend; -use frontend::lexer::Lexer; -use frontend::parser::{Parser,Node}; -use frontend::token::{Token, TokenType,Location}; -use frontend::utils::files::get_source_buffer; - -fn main() { - if let Some(source) = get_source_buffer("test_value.asm") { - // buffered reading - let mut ast_list: Vec> = vec![]; - for (line_no, read_buf) in source { - if let Ok(read_buf) = read_buf { - let mut l = Lexer::new(read_buf, line_no); - let mut tokns_buf: Vec = vec![]; - tokns_buf.push(Token::new(0,TokenType::BOL,Location::new(0,0),String::from("BOL"))); - - for tok in l { - tokns_buf.push(tok); - } - // println!("{:?}", tokns_buf); - - let mut p = Parser::new(tokns_buf.into_iter()); - ast_list.push(p.parse_expression()); - } else { - println!("Error reading!"); - } - println!("{:?}",ast_list); +// use frontend::lexer::Lexer; +// use frontend::parser::{Parser,Node}; +// use frontend::token::{Token, TokenType,Location}; +// use frontend::utils::files::get_source_buffer; + +use lsp_server::{Connection}; +use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities}; +use std::error::{Error}; + + +fn main() -> Result<(),Box >{ + + let (connection,io_threads) = Connection::stdio(); + + let (id,params) = connection.initialize_start()?; + + let init_params: InitializeParams = serde_json::from_value(params).unwrap(); + let client_capabilities: ClientCapabilities = init_params.capabilities; + let server_capabilities = ServerCapabilities::default(); + + + let initialize_data = serde_json::json!({ + "capabilities": server_capabilities, + "serverInfo": { + "name":"lsp-server", + "version":"0.1", } - } + }); + connection.initialize_finish(id,initialize_data); + + + Ok(()) + + + // if let Some(source) = get_source_buffer("test_value.asm") { + // // buffered reading + // let mut ast_list: Vec> = vec![]; + // for (line_no, read_buf) in source { + // if let Ok(read_buf) = read_buf { + // let mut l = Lexer::new(read_buf, line_no); + // let mut tokns_buf: Vec = vec![]; + // tokns_buf.push(Token::new(0,TokenType::BOL,Location::new(0,0),String::from("BOL"))); + + // for tok in l { + // tokns_buf.push(tok); + // } + // // println!("{:?}", tokns_buf); + + // let mut p = Parser::new(tokns_buf.into_iter()); + // ast_list.push(p.parse_expression()); + // } else { + // println!("Error reading!"); + // } + // println!("{:?}",ast_list); + // } + // } + + } diff --git a/src/server/mod.rs b/src/server/mod.rs index 8b13789..e69de29 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1 +0,0 @@ - From cd1e77071eb60d0530ce346fcf8521139fa20dc8 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 28 Nov 2025 15:42:59 +0545 Subject: [PATCH 19/50] add: lsp submodule --- .gitmodules | 3 + src/lsp/lsp85/.gitignore | 2 + src/lsp/lsp85/Cargo.toml | 8 + src/lsp/lsp85/grammar.txt | 21 ++ src/lsp/lsp85/src/frontend/lexer.rs | 222 ++++++++++++++++++++++ src/lsp/lsp85/src/frontend/mod.rs | 4 + src/lsp/lsp85/src/frontend/parser.rs | 128 +++++++++++++ src/lsp/lsp85/src/frontend/token.rs | 51 +++++ src/lsp/lsp85/src/frontend/utils/files.rs | 13 ++ src/lsp/lsp85/src/frontend/utils/mod.rs | 1 + src/lsp/lsp85/src/main.rs | 61 ++++++ src/lsp/lsp85/src/server/mod.rs | 0 src/lsp/lsp85/src/test_value.asm | 3 + 13 files changed, 517 insertions(+) create mode 100644 .gitmodules create mode 100644 src/lsp/lsp85/.gitignore create mode 100644 src/lsp/lsp85/Cargo.toml create mode 100644 src/lsp/lsp85/grammar.txt create mode 100644 src/lsp/lsp85/src/frontend/lexer.rs create mode 100644 src/lsp/lsp85/src/frontend/mod.rs create mode 100644 src/lsp/lsp85/src/frontend/parser.rs create mode 100644 src/lsp/lsp85/src/frontend/token.rs create mode 100644 src/lsp/lsp85/src/frontend/utils/files.rs create mode 100644 src/lsp/lsp85/src/frontend/utils/mod.rs create mode 100644 src/lsp/lsp85/src/main.rs create mode 100644 src/lsp/lsp85/src/server/mod.rs create mode 100644 src/lsp/lsp85/src/test_value.asm diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1b63a1c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/lsp85"] + path = src/lsp/lsp85 + url = git@github.com:shri-acha/lsp85.git diff --git a/src/lsp/lsp85/.gitignore b/src/lsp/lsp85/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/src/lsp/lsp85/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/src/lsp/lsp85/Cargo.toml b/src/lsp/lsp85/Cargo.toml new file mode 100644 index 0000000..d25331d --- /dev/null +++ b/src/lsp/lsp85/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "lsp85" +version = "0.1.0" +edition = "2024" + +[dependencies] +lsp-server = "0.7.9" +lsp-types = "0.97.0" diff --git a/src/lsp/lsp85/grammar.txt b/src/lsp/lsp85/grammar.txt new file mode 100644 index 0000000..38b3294 --- /dev/null +++ b/src/lsp/lsp85/grammar.txt @@ -0,0 +1,21 @@ + +OPCODE : ADD + |... + +REGISTER : A + | B + | C + | D + | E + | H + | L + | SP + | PSW + + : OPCODE + : REGISTER | NUM_LITERAL | e + : , REGISTER | , NUM_LITERAL | e + +ADD A B + +ADD REGISTER REGISTER diff --git a/src/lsp/lsp85/src/frontend/lexer.rs b/src/lsp/lsp85/src/frontend/lexer.rs new file mode 100644 index 0000000..6934cff --- /dev/null +++ b/src/lsp/lsp85/src/frontend/lexer.rs @@ -0,0 +1,222 @@ +use crate::frontend::token::{Location, Token, TokenType}; + +#[derive(Debug)] +pub struct Lexer { + pub source: String, // source string + pub ch: char, // current literal + pub curr_position: usize, // current position + pub read_position: usize, // next position + pub location: Location, // current location +} + +impl Lexer { + pub fn new(source: String, line_no: usize) -> Self { + Self { + ch: source.chars().nth(0).expect("source of size <1?"), + curr_position: 0, + read_position: 1, + location: Location { + row: line_no, + col: 0, + }, + source: source, + } + } +} + +impl Iterator for Lexer { + type Item = Token; + fn next(&mut self) -> Option { + match self.ch { + c if self.ch.is_alphabetic() => { + // identifier + return Some(self.read_identifier()); + } + c if self.ch.is_numeric() => { + return Some(self.read_immediate()); + } + ',' => { + self.consume(); + return Some(Token::new( + 1, + TokenType::COMMA_DELIM, + self.location, + String::from(','), + )); + } + ' ' => { + self.consume(); + return self.next(); + } + '\n' => { + self.consume(); + let buf_token = Some(Token::new( + 1, + TokenType::EOL, + self.location, + String::from('\n'), + )); + self.location.col = 0; + self.location.row += 1; + + return buf_token; + } + '\0' => { + return None; + } + _ => { + self.consume(); + return Some(Token::new( + 1, + TokenType::ILLEGAL, + self.location, + String::from('\0'), + )); + } + } + } +} +impl Lexer { + pub fn consume(&mut self) { + if self.read_position >= self.source.len() { + self.ch = '\0'; + } else { + self.ch = self.source.chars().nth(self.read_position).unwrap_or(' '); + } + self.curr_position = self.read_position; + self.read_position = self.curr_position + 1; + self.location.col += 1; + } + pub fn read_identifier(&mut self) -> Token { + let mut identifier_buf = String::from(""); + while self.ch.is_alphabetic() { + identifier_buf += &self.ch.to_string(); + self.consume(); + } + return Token::new( + identifier_buf.len(), + get_identifier_token(&identifier_buf), + self.location, + identifier_buf, + ); + } + pub fn read_immediate(&mut self) -> Token { + let mut immediate_buf = String::from(""); + + //Support for hex digits + while self.ch.is_ascii_hexdigit() { + immediate_buf += &self.ch.to_string(); + self.consume(); + } + + //H suffix handling Eg: 123AH + if self.ch == 'H' { + immediate_buf += &self.ch.to_string(); + self.consume(); + } + return Token::new( + immediate_buf.len(), + TokenType::IMM_VALUE, + self.location, + immediate_buf, + ); + } +} +fn get_identifier_token(identifier_lit: &String) -> TokenType { + match identifier_lit.as_str() { + "ADD" | "SUB" | "MOV" | "MVI" | "LXI" | "PUSH" | "POP" | "INR" | "DCR" | "DAD" | "LDAX" + | "STAX" => { + return TokenType::OPERATION; + } + "A" | "B" | "C" | "D" | "E" | "PSW" | "H" | "L" | "SP" => { + return TokenType::REGISTER; + } + _ => { + return TokenType::ILLEGAL; + } + } +} + +#[cfg(test)] +mod tests { + + use super::Lexer; + use crate::frontend::token::{Location, Token, TokenType}; + #[test] + fn imm_test() { + let source = String::from("MVI A,05H\n"); + let mut l = Lexer::new(source,0); + let mut tokens: Vec = vec![]; + for token in l { + tokens.push(token); + } + + assert_eq!( + vec![ + Token::new( + 3, + TokenType::OPERATION, + Location::new(0, 3), + "MVI".to_string()), + Token::new( + 1, + TokenType::REGISTER, + Location::new(0, 5), + "A".to_string()), + Token::new( + 1, + TokenType::COMMA_DELIM, + Location::new(0, 6), + ",".to_string()), + Token::new( + 3, + TokenType::IMM_VALUE, + Location::new(0, 9), + "05H".to_string()), + Token::new( + 1, + TokenType::EOL, + Location::new(0, 10), + "\n".to_string()) + ], + tokens + ); + } + + #[test] + fn reg_pair() { + let source = String::from("MVI A,SP\n"); + let mut l = Lexer::new(source,0); + let mut tokens: Vec = vec![]; + for token in l { + tokens.push(token); + } + + assert_eq!( + vec![ + Token::new( + 3, + TokenType::OPERATION, + Location::new(0, 3), + "MVI".to_string()), + Token::new( 1, TokenType::REGISTER, Location::new(0, 5), "A".to_string()), + Token::new( + 1, + TokenType::COMMA_DELIM, + Location::new(0, 6), + ",".to_string()), + Token::new( + 2, + TokenType::REGISTER, + Location::new(0, 8), + "SP".to_string()), + Token::new( + 1, + TokenType::EOL, + Location::new(0, 9), + "\n".to_string()) + ], + tokens + ); + } +} diff --git a/src/lsp/lsp85/src/frontend/mod.rs b/src/lsp/lsp85/src/frontend/mod.rs new file mode 100644 index 0000000..306e9fa --- /dev/null +++ b/src/lsp/lsp85/src/frontend/mod.rs @@ -0,0 +1,4 @@ +pub mod lexer; +pub mod parser; +pub mod token; +pub mod utils; diff --git a/src/lsp/lsp85/src/frontend/parser.rs b/src/lsp/lsp85/src/frontend/parser.rs new file mode 100644 index 0000000..3df4ffc --- /dev/null +++ b/src/lsp/lsp85/src/frontend/parser.rs @@ -0,0 +1,128 @@ +use crate::frontend::token::{Token, TokenType}; +use std::iter::Peekable; +use std::vec::IntoIter; + +#[derive(Debug)] +pub struct Parser { + tok_stream: Peekable>, +} +impl Parser { + pub fn new(tok_stream: IntoIter) -> Self { + Self { + tok_stream: tok_stream.peekable(), + } + } +} + +#[derive(Debug,PartialEq)] +pub struct Tree{ + pub l_child: Option, + pub r_child: Option, +} + +impl Tree { + pub fn default()->Self{ + Self{ + l_child:None, + r_child:None, + } + } + + pub fn new(l_child:Option,r_child: Option)->Self{ + Self{ + l_child, + r_child + } + } +} +#[derive(Debug,PartialEq)] +pub struct Node { + pub value: Token, + pub branch: Box +} + +impl Node{ + pub fn new(tok_val: Token, branch: Box)->Self{ + Self{ + value: tok_val, + branch + } + } +} + +impl Parser { + pub fn parse_expression(&mut self)->Option{ + + if let Some(peeked_token) = self.tok_stream.peek(){ + println!("parse_expression() called! {:?}",peeked_token); + match peeked_token { + Token{tok_type: TokenType::OPERATION,..}=>{ + return self.parse_operation(); + }, + Token{tok_type: TokenType::REGISTER, ..}=>{ + println!("unexpected placement of register!"); + return None; + } + Token{tok_type: TokenType::EOF, ..}=>{ + return None; + } + _ =>{ + self.tok_stream.next(); + return self.parse_expression(); + } + } + }else{ + return None; + } + } + pub fn parse_operation(&mut self)->Option{ + let mut l_child: Node; + if let Some(peeked_token) = self.tok_stream.peek(){ + l_child = Node::new(peeked_token.clone(),Box::new(Tree::default())); + }else{ + return None; + } + self.tok_stream.next(); + if let Some(peeked_token) = self.tok_stream.peek(){ + match peeked_token{ + Token{ tok_type: TokenType::REGISTER, .. }=>{ + l_child.branch.l_child = self.parse_operand(); + l_child.branch.r_child = self.parse_operand(); + return Some(l_child); + }, + _=>{ + return Some(l_child); + } + } + }else{ + return Some(l_child); + } + } + pub fn parse_operand(&mut self)->Option{ + + let mut l_child: Node; + if let Some(peeked_token) = self.tok_stream.peek(){ + match peeked_token{ + Token{tok_type: TokenType:: REGISTER, .. }=>{ + let token_buffer = peeked_token.clone(); + self.tok_stream.next(); + return Some(Node::new(token_buffer,Box::new(Tree::default()))); + }, + Token{tok_type: TokenType:: COMMA_DELIM, .. }=>{ + self.tok_stream.next(); + return self.parse_operand(); + }, + Token{tok_type: TokenType:: IMM_VALUE, .. }=>{ + let token_buffer = peeked_token.clone(); + self.tok_stream.next(); + return Some(Node::new(token_buffer,Box::new(Tree::default()))); + }, + _ =>{ + return None; + } + } + }else{ + return None; + } + } +} diff --git a/src/lsp/lsp85/src/frontend/token.rs b/src/lsp/lsp85/src/frontend/token.rs new file mode 100644 index 0000000..cada4bb --- /dev/null +++ b/src/lsp/lsp85/src/frontend/token.rs @@ -0,0 +1,51 @@ +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Location { + pub row: usize, + pub col: usize, +} +impl Location { + pub fn new(row: usize, col: usize) -> Self { + Self { row, col } + } +} + +#[derive(Debug,Clone,PartialEq)] +pub struct Token { + pub tok_literal: String, + pub tok_type: TokenType, + pub location: Location, + pub offset: usize, // -ve char offset +} + +impl Token { + pub fn new( + offset: usize, + tok_type: TokenType, + location: Location, + tok_literal: String, + ) -> Self { + Self { + tok_literal, + tok_type, + location, + offset, + } + } +} + +// ADD A,B +// +// INSTRUCTION +// OPERATION REGISTER COMMA_DELIM REGISTER +// +#[derive(Debug,Copy,Clone,PartialEq)] +pub enum TokenType { + OPERATION, + IMM_VALUE, + REGISTER, + COMMA_DELIM, + BOL, + EOL, + EOF, + ILLEGAL, +} diff --git a/src/lsp/lsp85/src/frontend/utils/files.rs b/src/lsp/lsp85/src/frontend/utils/files.rs new file mode 100644 index 0000000..3d7f2a8 --- /dev/null +++ b/src/lsp/lsp85/src/frontend/utils/files.rs @@ -0,0 +1,13 @@ +use std::fs::File; +use std::io::BufRead; +use std::io::BufReader; +use std::io::Lines; +use std::io::Read; +use std::iter::Enumerate; + +pub fn get_source_buffer(f_name: &'static str) -> Option>>> { + let file = File::open(f_name).ok()?; + let buffer = BufReader::new(file); + let lines = buffer.lines().enumerate(); + return Some(lines); +} diff --git a/src/lsp/lsp85/src/frontend/utils/mod.rs b/src/lsp/lsp85/src/frontend/utils/mod.rs new file mode 100644 index 0000000..d3ab969 --- /dev/null +++ b/src/lsp/lsp85/src/frontend/utils/mod.rs @@ -0,0 +1 @@ +pub mod files; diff --git a/src/lsp/lsp85/src/main.rs b/src/lsp/lsp85/src/main.rs new file mode 100644 index 0000000..5b7438f --- /dev/null +++ b/src/lsp/lsp85/src/main.rs @@ -0,0 +1,61 @@ +mod frontend; + +// use frontend::lexer::Lexer; +// use frontend::parser::{Parser,Node}; +// use frontend::token::{Token, TokenType,Location}; +// use frontend::utils::files::get_source_buffer; + +use lsp_server::{Connection}; +use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities}; +use std::error::{Error}; + + +fn main() -> Result<(),Box >{ + + let (connection,io_threads) = Connection::stdio(); + + let (id,params) = connection.initialize_start()?; + + let init_params: InitializeParams = serde_json::from_value(params).unwrap(); + let client_capabilities: ClientCapabilities = init_params.capabilities; + let server_capabilities = ServerCapabilities::default(); + + + let initialize_data = serde_json::json!({ + "capabilities": server_capabilities, + "serverInfo": { + "name":"lsp-server", + "version":"0.1", + } + }); + connection.initialize_finish(id,initialize_data); + + + Ok(()) + + + // if let Some(source) = get_source_buffer("test_value.asm") { + // // buffered reading + // let mut ast_list: Vec> = vec![]; + // for (line_no, read_buf) in source { + // if let Ok(read_buf) = read_buf { + // let mut l = Lexer::new(read_buf, line_no); + // let mut tokns_buf: Vec = vec![]; + // tokns_buf.push(Token::new(0,TokenType::BOL,Location::new(0,0),String::from("BOL"))); + + // for tok in l { + // tokns_buf.push(tok); + // } + // // println!("{:?}", tokns_buf); + + // let mut p = Parser::new(tokns_buf.into_iter()); + // ast_list.push(p.parse_expression()); + // } else { + // println!("Error reading!"); + // } + // println!("{:?}",ast_list); + // } + // } + + +} diff --git a/src/lsp/lsp85/src/server/mod.rs b/src/lsp/lsp85/src/server/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/lsp/lsp85/src/test_value.asm b/src/lsp/lsp85/src/test_value.asm new file mode 100644 index 0000000..87833e6 --- /dev/null +++ b/src/lsp/lsp85/src/test_value.asm @@ -0,0 +1,3 @@ +MVI SP,0001H +MOV B,A +MVI B,00H From d1bced137b2d3b320095b973c21c5090e3057062 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 28 Nov 2025 16:23:35 +0545 Subject: [PATCH 20/50] chore: edit gitmodules --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 1b63a1c..c271c38 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "src/lsp85"] +[submodule "src/lsp/lsp85"] path = src/lsp/lsp85 url = git@github.com:shri-acha/lsp85.git From 0bea56d4eed998f5d6d86fa7ce4501530bf69e2b Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 28 Nov 2025 16:33:59 +0545 Subject: [PATCH 21/50] chore: fixing submodule initialization --- src/lsp/lsp85/.gitignore | 2 - src/lsp/lsp85/Cargo.toml | 8 - src/lsp/lsp85/grammar.txt | 21 -- src/lsp/lsp85/src/frontend/lexer.rs | 222 ---------------------- src/lsp/lsp85/src/frontend/mod.rs | 4 - src/lsp/lsp85/src/frontend/parser.rs | 128 ------------- src/lsp/lsp85/src/frontend/token.rs | 51 ----- src/lsp/lsp85/src/frontend/utils/files.rs | 13 -- src/lsp/lsp85/src/frontend/utils/mod.rs | 1 - src/lsp/lsp85/src/main.rs | 61 ------ src/lsp/lsp85/src/server/mod.rs | 0 src/lsp/lsp85/src/test_value.asm | 3 - 12 files changed, 514 deletions(-) delete mode 100644 src/lsp/lsp85/.gitignore delete mode 100644 src/lsp/lsp85/Cargo.toml delete mode 100644 src/lsp/lsp85/grammar.txt delete mode 100644 src/lsp/lsp85/src/frontend/lexer.rs delete mode 100644 src/lsp/lsp85/src/frontend/mod.rs delete mode 100644 src/lsp/lsp85/src/frontend/parser.rs delete mode 100644 src/lsp/lsp85/src/frontend/token.rs delete mode 100644 src/lsp/lsp85/src/frontend/utils/files.rs delete mode 100644 src/lsp/lsp85/src/frontend/utils/mod.rs delete mode 100644 src/lsp/lsp85/src/main.rs delete mode 100644 src/lsp/lsp85/src/server/mod.rs delete mode 100644 src/lsp/lsp85/src/test_value.asm diff --git a/src/lsp/lsp85/.gitignore b/src/lsp/lsp85/.gitignore deleted file mode 100644 index 96ef6c0..0000000 --- a/src/lsp/lsp85/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/src/lsp/lsp85/Cargo.toml b/src/lsp/lsp85/Cargo.toml deleted file mode 100644 index d25331d..0000000 --- a/src/lsp/lsp85/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "lsp85" -version = "0.1.0" -edition = "2024" - -[dependencies] -lsp-server = "0.7.9" -lsp-types = "0.97.0" diff --git a/src/lsp/lsp85/grammar.txt b/src/lsp/lsp85/grammar.txt deleted file mode 100644 index 38b3294..0000000 --- a/src/lsp/lsp85/grammar.txt +++ /dev/null @@ -1,21 +0,0 @@ - -OPCODE : ADD - |... - -REGISTER : A - | B - | C - | D - | E - | H - | L - | SP - | PSW - - : OPCODE - : REGISTER | NUM_LITERAL | e - : , REGISTER | , NUM_LITERAL | e - -ADD A B - -ADD REGISTER REGISTER diff --git a/src/lsp/lsp85/src/frontend/lexer.rs b/src/lsp/lsp85/src/frontend/lexer.rs deleted file mode 100644 index 6934cff..0000000 --- a/src/lsp/lsp85/src/frontend/lexer.rs +++ /dev/null @@ -1,222 +0,0 @@ -use crate::frontend::token::{Location, Token, TokenType}; - -#[derive(Debug)] -pub struct Lexer { - pub source: String, // source string - pub ch: char, // current literal - pub curr_position: usize, // current position - pub read_position: usize, // next position - pub location: Location, // current location -} - -impl Lexer { - pub fn new(source: String, line_no: usize) -> Self { - Self { - ch: source.chars().nth(0).expect("source of size <1?"), - curr_position: 0, - read_position: 1, - location: Location { - row: line_no, - col: 0, - }, - source: source, - } - } -} - -impl Iterator for Lexer { - type Item = Token; - fn next(&mut self) -> Option { - match self.ch { - c if self.ch.is_alphabetic() => { - // identifier - return Some(self.read_identifier()); - } - c if self.ch.is_numeric() => { - return Some(self.read_immediate()); - } - ',' => { - self.consume(); - return Some(Token::new( - 1, - TokenType::COMMA_DELIM, - self.location, - String::from(','), - )); - } - ' ' => { - self.consume(); - return self.next(); - } - '\n' => { - self.consume(); - let buf_token = Some(Token::new( - 1, - TokenType::EOL, - self.location, - String::from('\n'), - )); - self.location.col = 0; - self.location.row += 1; - - return buf_token; - } - '\0' => { - return None; - } - _ => { - self.consume(); - return Some(Token::new( - 1, - TokenType::ILLEGAL, - self.location, - String::from('\0'), - )); - } - } - } -} -impl Lexer { - pub fn consume(&mut self) { - if self.read_position >= self.source.len() { - self.ch = '\0'; - } else { - self.ch = self.source.chars().nth(self.read_position).unwrap_or(' '); - } - self.curr_position = self.read_position; - self.read_position = self.curr_position + 1; - self.location.col += 1; - } - pub fn read_identifier(&mut self) -> Token { - let mut identifier_buf = String::from(""); - while self.ch.is_alphabetic() { - identifier_buf += &self.ch.to_string(); - self.consume(); - } - return Token::new( - identifier_buf.len(), - get_identifier_token(&identifier_buf), - self.location, - identifier_buf, - ); - } - pub fn read_immediate(&mut self) -> Token { - let mut immediate_buf = String::from(""); - - //Support for hex digits - while self.ch.is_ascii_hexdigit() { - immediate_buf += &self.ch.to_string(); - self.consume(); - } - - //H suffix handling Eg: 123AH - if self.ch == 'H' { - immediate_buf += &self.ch.to_string(); - self.consume(); - } - return Token::new( - immediate_buf.len(), - TokenType::IMM_VALUE, - self.location, - immediate_buf, - ); - } -} -fn get_identifier_token(identifier_lit: &String) -> TokenType { - match identifier_lit.as_str() { - "ADD" | "SUB" | "MOV" | "MVI" | "LXI" | "PUSH" | "POP" | "INR" | "DCR" | "DAD" | "LDAX" - | "STAX" => { - return TokenType::OPERATION; - } - "A" | "B" | "C" | "D" | "E" | "PSW" | "H" | "L" | "SP" => { - return TokenType::REGISTER; - } - _ => { - return TokenType::ILLEGAL; - } - } -} - -#[cfg(test)] -mod tests { - - use super::Lexer; - use crate::frontend::token::{Location, Token, TokenType}; - #[test] - fn imm_test() { - let source = String::from("MVI A,05H\n"); - let mut l = Lexer::new(source,0); - let mut tokens: Vec = vec![]; - for token in l { - tokens.push(token); - } - - assert_eq!( - vec![ - Token::new( - 3, - TokenType::OPERATION, - Location::new(0, 3), - "MVI".to_string()), - Token::new( - 1, - TokenType::REGISTER, - Location::new(0, 5), - "A".to_string()), - Token::new( - 1, - TokenType::COMMA_DELIM, - Location::new(0, 6), - ",".to_string()), - Token::new( - 3, - TokenType::IMM_VALUE, - Location::new(0, 9), - "05H".to_string()), - Token::new( - 1, - TokenType::EOL, - Location::new(0, 10), - "\n".to_string()) - ], - tokens - ); - } - - #[test] - fn reg_pair() { - let source = String::from("MVI A,SP\n"); - let mut l = Lexer::new(source,0); - let mut tokens: Vec = vec![]; - for token in l { - tokens.push(token); - } - - assert_eq!( - vec![ - Token::new( - 3, - TokenType::OPERATION, - Location::new(0, 3), - "MVI".to_string()), - Token::new( 1, TokenType::REGISTER, Location::new(0, 5), "A".to_string()), - Token::new( - 1, - TokenType::COMMA_DELIM, - Location::new(0, 6), - ",".to_string()), - Token::new( - 2, - TokenType::REGISTER, - Location::new(0, 8), - "SP".to_string()), - Token::new( - 1, - TokenType::EOL, - Location::new(0, 9), - "\n".to_string()) - ], - tokens - ); - } -} diff --git a/src/lsp/lsp85/src/frontend/mod.rs b/src/lsp/lsp85/src/frontend/mod.rs deleted file mode 100644 index 306e9fa..0000000 --- a/src/lsp/lsp85/src/frontend/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod lexer; -pub mod parser; -pub mod token; -pub mod utils; diff --git a/src/lsp/lsp85/src/frontend/parser.rs b/src/lsp/lsp85/src/frontend/parser.rs deleted file mode 100644 index 3df4ffc..0000000 --- a/src/lsp/lsp85/src/frontend/parser.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::frontend::token::{Token, TokenType}; -use std::iter::Peekable; -use std::vec::IntoIter; - -#[derive(Debug)] -pub struct Parser { - tok_stream: Peekable>, -} -impl Parser { - pub fn new(tok_stream: IntoIter) -> Self { - Self { - tok_stream: tok_stream.peekable(), - } - } -} - -#[derive(Debug,PartialEq)] -pub struct Tree{ - pub l_child: Option, - pub r_child: Option, -} - -impl Tree { - pub fn default()->Self{ - Self{ - l_child:None, - r_child:None, - } - } - - pub fn new(l_child:Option,r_child: Option)->Self{ - Self{ - l_child, - r_child - } - } -} -#[derive(Debug,PartialEq)] -pub struct Node { - pub value: Token, - pub branch: Box -} - -impl Node{ - pub fn new(tok_val: Token, branch: Box)->Self{ - Self{ - value: tok_val, - branch - } - } -} - -impl Parser { - pub fn parse_expression(&mut self)->Option{ - - if let Some(peeked_token) = self.tok_stream.peek(){ - println!("parse_expression() called! {:?}",peeked_token); - match peeked_token { - Token{tok_type: TokenType::OPERATION,..}=>{ - return self.parse_operation(); - }, - Token{tok_type: TokenType::REGISTER, ..}=>{ - println!("unexpected placement of register!"); - return None; - } - Token{tok_type: TokenType::EOF, ..}=>{ - return None; - } - _ =>{ - self.tok_stream.next(); - return self.parse_expression(); - } - } - }else{ - return None; - } - } - pub fn parse_operation(&mut self)->Option{ - let mut l_child: Node; - if let Some(peeked_token) = self.tok_stream.peek(){ - l_child = Node::new(peeked_token.clone(),Box::new(Tree::default())); - }else{ - return None; - } - self.tok_stream.next(); - if let Some(peeked_token) = self.tok_stream.peek(){ - match peeked_token{ - Token{ tok_type: TokenType::REGISTER, .. }=>{ - l_child.branch.l_child = self.parse_operand(); - l_child.branch.r_child = self.parse_operand(); - return Some(l_child); - }, - _=>{ - return Some(l_child); - } - } - }else{ - return Some(l_child); - } - } - pub fn parse_operand(&mut self)->Option{ - - let mut l_child: Node; - if let Some(peeked_token) = self.tok_stream.peek(){ - match peeked_token{ - Token{tok_type: TokenType:: REGISTER, .. }=>{ - let token_buffer = peeked_token.clone(); - self.tok_stream.next(); - return Some(Node::new(token_buffer,Box::new(Tree::default()))); - }, - Token{tok_type: TokenType:: COMMA_DELIM, .. }=>{ - self.tok_stream.next(); - return self.parse_operand(); - }, - Token{tok_type: TokenType:: IMM_VALUE, .. }=>{ - let token_buffer = peeked_token.clone(); - self.tok_stream.next(); - return Some(Node::new(token_buffer,Box::new(Tree::default()))); - }, - _ =>{ - return None; - } - } - }else{ - return None; - } - } -} diff --git a/src/lsp/lsp85/src/frontend/token.rs b/src/lsp/lsp85/src/frontend/token.rs deleted file mode 100644 index cada4bb..0000000 --- a/src/lsp/lsp85/src/frontend/token.rs +++ /dev/null @@ -1,51 +0,0 @@ -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Location { - pub row: usize, - pub col: usize, -} -impl Location { - pub fn new(row: usize, col: usize) -> Self { - Self { row, col } - } -} - -#[derive(Debug,Clone,PartialEq)] -pub struct Token { - pub tok_literal: String, - pub tok_type: TokenType, - pub location: Location, - pub offset: usize, // -ve char offset -} - -impl Token { - pub fn new( - offset: usize, - tok_type: TokenType, - location: Location, - tok_literal: String, - ) -> Self { - Self { - tok_literal, - tok_type, - location, - offset, - } - } -} - -// ADD A,B -// -// INSTRUCTION -// OPERATION REGISTER COMMA_DELIM REGISTER -// -#[derive(Debug,Copy,Clone,PartialEq)] -pub enum TokenType { - OPERATION, - IMM_VALUE, - REGISTER, - COMMA_DELIM, - BOL, - EOL, - EOF, - ILLEGAL, -} diff --git a/src/lsp/lsp85/src/frontend/utils/files.rs b/src/lsp/lsp85/src/frontend/utils/files.rs deleted file mode 100644 index 3d7f2a8..0000000 --- a/src/lsp/lsp85/src/frontend/utils/files.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::fs::File; -use std::io::BufRead; -use std::io::BufReader; -use std::io::Lines; -use std::io::Read; -use std::iter::Enumerate; - -pub fn get_source_buffer(f_name: &'static str) -> Option>>> { - let file = File::open(f_name).ok()?; - let buffer = BufReader::new(file); - let lines = buffer.lines().enumerate(); - return Some(lines); -} diff --git a/src/lsp/lsp85/src/frontend/utils/mod.rs b/src/lsp/lsp85/src/frontend/utils/mod.rs deleted file mode 100644 index d3ab969..0000000 --- a/src/lsp/lsp85/src/frontend/utils/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod files; diff --git a/src/lsp/lsp85/src/main.rs b/src/lsp/lsp85/src/main.rs deleted file mode 100644 index 5b7438f..0000000 --- a/src/lsp/lsp85/src/main.rs +++ /dev/null @@ -1,61 +0,0 @@ -mod frontend; - -// use frontend::lexer::Lexer; -// use frontend::parser::{Parser,Node}; -// use frontend::token::{Token, TokenType,Location}; -// use frontend::utils::files::get_source_buffer; - -use lsp_server::{Connection}; -use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities}; -use std::error::{Error}; - - -fn main() -> Result<(),Box >{ - - let (connection,io_threads) = Connection::stdio(); - - let (id,params) = connection.initialize_start()?; - - let init_params: InitializeParams = serde_json::from_value(params).unwrap(); - let client_capabilities: ClientCapabilities = init_params.capabilities; - let server_capabilities = ServerCapabilities::default(); - - - let initialize_data = serde_json::json!({ - "capabilities": server_capabilities, - "serverInfo": { - "name":"lsp-server", - "version":"0.1", - } - }); - connection.initialize_finish(id,initialize_data); - - - Ok(()) - - - // if let Some(source) = get_source_buffer("test_value.asm") { - // // buffered reading - // let mut ast_list: Vec> = vec![]; - // for (line_no, read_buf) in source { - // if let Ok(read_buf) = read_buf { - // let mut l = Lexer::new(read_buf, line_no); - // let mut tokns_buf: Vec = vec![]; - // tokns_buf.push(Token::new(0,TokenType::BOL,Location::new(0,0),String::from("BOL"))); - - // for tok in l { - // tokns_buf.push(tok); - // } - // // println!("{:?}", tokns_buf); - - // let mut p = Parser::new(tokns_buf.into_iter()); - // ast_list.push(p.parse_expression()); - // } else { - // println!("Error reading!"); - // } - // println!("{:?}",ast_list); - // } - // } - - -} diff --git a/src/lsp/lsp85/src/server/mod.rs b/src/lsp/lsp85/src/server/mod.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/lsp/lsp85/src/test_value.asm b/src/lsp/lsp85/src/test_value.asm deleted file mode 100644 index 87833e6..0000000 --- a/src/lsp/lsp85/src/test_value.asm +++ /dev/null @@ -1,3 +0,0 @@ -MVI SP,0001H -MOV B,A -MVI B,00H From f4e7e4ca8d862df322ca4f2dd6261b15a7f385bd Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 28 Nov 2025 16:35:45 +0545 Subject: [PATCH 22/50] chore: fixed submodule initialization --- .gitmodules | 2 +- src/lsp/lsp85 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 160000 src/lsp/lsp85 diff --git a/.gitmodules b/.gitmodules index c271c38..3e27885 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "src/lsp/lsp85"] path = src/lsp/lsp85 - url = git@github.com:shri-acha/lsp85.git + url = git@github.com:shri-acha/lsp85.git/ diff --git a/src/lsp/lsp85 b/src/lsp/lsp85 new file mode 160000 index 0000000..bb184b9 --- /dev/null +++ b/src/lsp/lsp85 @@ -0,0 +1 @@ +Subproject commit bb184b92f82c3caa8ca5c555d01d455ae0d2379c From f7abf03a5ddf17fe4ff8f065097db19996689ab0 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 28 Nov 2025 20:21:58 +0545 Subject: [PATCH 23/50] chore: cleanup --- src/main.rs | 12 ++++++++++-- src/test_value.asm | 3 --- 2 files changed, 10 insertions(+), 5 deletions(-) delete mode 100644 src/test_value.asm diff --git a/src/main.rs b/src/main.rs index 5b7438f..f495c2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod frontend; +mod server; // use frontend::lexer::Lexer; // use frontend::parser::{Parser,Node}; @@ -8,6 +9,7 @@ mod frontend; use lsp_server::{Connection}; use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities}; use std::error::{Error}; +use server::{debug_send_message}; fn main() -> Result<(),Box >{ @@ -15,6 +17,7 @@ fn main() -> Result<(),Box >{ let (connection,io_threads) = Connection::stdio(); let (id,params) = connection.initialize_start()?; + eprintln!("Connection initialized!"); let init_params: InitializeParams = serde_json::from_value(params).unwrap(); let client_capabilities: ClientCapabilities = init_params.capabilities; @@ -24,13 +27,18 @@ fn main() -> Result<(),Box >{ let initialize_data = serde_json::json!({ "capabilities": server_capabilities, "serverInfo": { - "name":"lsp-server", + "name":"lsp85", "version":"0.1", } }); - connection.initialize_finish(id,initialize_data); + connection.initialize_finish(id,initialize_data)?; + + for msg in &connection.receiver { + eprintln!("{:?}",msg); + } + io_threads.join()?; Ok(()) diff --git a/src/test_value.asm b/src/test_value.asm deleted file mode 100644 index 87833e6..0000000 --- a/src/test_value.asm +++ /dev/null @@ -1,3 +0,0 @@ -MVI SP,0001H -MOV B,A -MVI B,00H From db6435aee8b525734c598dc08229507aeccdc133 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Sat, 29 Nov 2025 08:38:56 +0545 Subject: [PATCH 24/50] feat: pattern matching and detection of requests --- src/main.rs | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index f495c2b..b8b4864 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,10 +6,9 @@ mod server; // use frontend::token::{Token, TokenType,Location}; // use frontend::utils::files::get_source_buffer; -use lsp_server::{Connection}; -use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities}; +use lsp_server::{Connection,Message,Notification,Request}; +use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities,CompletionOptions}; use std::error::{Error}; -use server::{debug_send_message}; fn main() -> Result<(),Box >{ @@ -21,7 +20,9 @@ fn main() -> Result<(),Box >{ let init_params: InitializeParams = serde_json::from_value(params).unwrap(); let client_capabilities: ClientCapabilities = init_params.capabilities; - let server_capabilities = ServerCapabilities::default(); + let mut server_capabilities = ServerCapabilities::default(); + + server_capabilities.completion_provider = Some(CompletionOptions::default()); let initialize_data = serde_json::json!({ @@ -34,7 +35,33 @@ fn main() -> Result<(),Box >{ connection.initialize_finish(id,initialize_data)?; for msg in &connection.receiver { - eprintln!("{:?}",msg); + match &msg{ + Message::Request(rq)=>{ + match rq{ + Request{ method:method, .. } if *method == String::from("Close") =>{ + eprintln!("Close called!"); + } + e =>{ + eprintln!("unimplemented {:?}",e) + } + } + eprintln!("request: {:?}",rq); + } + Message::Response(rs)=>{ + eprintln!("response: {:?}",rs); + } + Message::Notification(n)=>{ + match n { + Notification{ method:method, .. } if *method == String::from("textDocument/didSave") =>{ + eprintln!("File saved!"); + } + e =>{ + eprintln!("unimplemented {:?}",e) + } + } + eprintln!("notification: {:?}",n); + } + } } @@ -64,6 +91,5 @@ fn main() -> Result<(),Box >{ // println!("{:?}",ast_list); // } // } - } From e9bf65eff33634d0dc76f57385f4077dcd1f6814 Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Sat, 29 Nov 2025 12:54:04 +0545 Subject: [PATCH 25/50] Feat: added dummy textDocument/completion --- Cargo.toml | 3 ++ debug.log | 14 +++++++++ src/main.rs | 82 +++++++++++++++++++++++++++++++++-------------------- 3 files changed, 68 insertions(+), 31 deletions(-) create mode 100644 debug.log diff --git a/Cargo.toml b/Cargo.toml index d25331d..627f628 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,6 @@ edition = "2024" [dependencies] lsp-server = "0.7.9" lsp-types = "0.97.0" +serde = { version = "1", features = ["derive"] } +serde_json = "1" + diff --git a/debug.log b/debug.log new file mode 100644 index 0000000..4151ac7 --- /dev/null +++ b/debug.log @@ -0,0 +1,14 @@ +[12:28:39] LSP Server starting... +[12:28:39] Connection established +[12:28:39] Initialize start: id=RequestId(I32(1)) +[12:28:42] Initialize finished, entering main loop +[12:28:50] Received message: Request(Request { id: RequestId(I32(2)), method: "shutdown", params: Null }) +[12:28:50] Request method: shutdown +[12:28:50] Unhandled request: shutdown +[12:28:51] LSP Server starting... +[12:28:51] Connection established +[12:28:51] Initialize start: id=RequestId(I32(1)) +[12:28:52] Initialize finished, entering main loop +[12:30:26] Received message: Request(Request { id: RequestId(I32(2)), method: "shutdown", params: Null }) +[12:30:26] Request method: shutdown +[12:30:26] Unhandled request: shutdown diff --git a/src/main.rs b/src/main.rs index b8b4864..447a4f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,25 +6,25 @@ mod server; // use frontend::token::{Token, TokenType,Location}; // use frontend::utils::files::get_source_buffer; -use lsp_server::{Connection,Message,Notification,Request}; -use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities,CompletionOptions}; -use std::error::{Error}; +use lsp_server::{Connection, Message, Notification, Request, Response}; +use lsp_types::{ + ClientCapabilities, CompletionItem, CompletionOptions, CompletionResponse, InitializeParams, + ServerCapabilities, +}; +use std::error::Error; +fn main() -> Result<(), Box> { + let (connection, io_threads) = Connection::stdio(); -fn main() -> Result<(),Box >{ - - let (connection,io_threads) = Connection::stdio(); - - let (id,params) = connection.initialize_start()?; + let (id, params) = connection.initialize_start()?; eprintln!("Connection initialized!"); let init_params: InitializeParams = serde_json::from_value(params).unwrap(); let client_capabilities: ClientCapabilities = init_params.capabilities; - let mut server_capabilities = ServerCapabilities::default(); + let mut server_capabilities = ServerCapabilities::default(); server_capabilities.completion_provider = Some(CompletionOptions::default()); - let initialize_data = serde_json::json!({ "capabilities": server_capabilities, "serverInfo": { @@ -32,43 +32,64 @@ fn main() -> Result<(),Box >{ "version":"0.1", } }); - connection.initialize_finish(id,initialize_data)?; - + connection.initialize_finish(id, initialize_data)?; + for msg in &connection.receiver { - match &msg{ - Message::Request(rq)=>{ - match rq{ - Request{ method:method, .. } if *method == String::from("Close") =>{ + match &msg { + Message::Request(req) => { + match req { + Request { method, .. } if *method == String::from("Close") => { + eprintln!("Close called!"); + } + Request { method, .. } + if *method == String::from("textDocument/completion") => + { eprintln!("Close called!"); + let sample_responses = vec![ + CompletionItem::new_simple( + "MOV".to_string(), + "Move instruction".to_string(), + ), + CompletionItem::new_simple( + "SUB".to_string(), + "Subtract instruction".to_string(), + ), + CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), + ]; + let resp = Response::new_ok( + req.id.clone(), + CompletionResponse::Array(sample_responses), + ); + connection.sender.send(Message::Response(resp))?; } - e =>{ - eprintln!("unimplemented {:?}",e) + e => { + eprintln!("unimplemented {:?}", e) } } - eprintln!("request: {:?}",rq); - } - Message::Response(rs)=>{ - eprintln!("response: {:?}",rs); - } - Message::Notification(n)=>{ + eprintln!("request: {:?}", req); + } + Message::Response(rs) => { + eprintln!("response: {:?}", rs); + } + Message::Notification(n) => { match n { - Notification{ method:method, .. } if *method == String::from("textDocument/didSave") =>{ + Notification { method, .. } + if *method == String::from("textDocument/didSave") => + { eprintln!("File saved!"); } - e =>{ - eprintln!("unimplemented {:?}",e) + e => { + eprintln!("unimplemented {:?}", e) } } - eprintln!("notification: {:?}",n); + eprintln!("notification: {:?}", n); } } } - io_threads.join()?; Ok(()) - // if let Some(source) = get_source_buffer("test_value.asm") { // // buffered reading // let mut ast_list: Vec> = vec![]; @@ -91,5 +112,4 @@ fn main() -> Result<(),Box >{ // println!("{:?}",ast_list); // } // } - } From 618bbd34eb5f279a9f7e02976f119b77425d21f5 Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Sat, 29 Nov 2025 12:55:51 +0545 Subject: [PATCH 26/50] Chore: deleted debug.log --- debug.log | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 debug.log diff --git a/debug.log b/debug.log deleted file mode 100644 index 4151ac7..0000000 --- a/debug.log +++ /dev/null @@ -1,14 +0,0 @@ -[12:28:39] LSP Server starting... -[12:28:39] Connection established -[12:28:39] Initialize start: id=RequestId(I32(1)) -[12:28:42] Initialize finished, entering main loop -[12:28:50] Received message: Request(Request { id: RequestId(I32(2)), method: "shutdown", params: Null }) -[12:28:50] Request method: shutdown -[12:28:50] Unhandled request: shutdown -[12:28:51] LSP Server starting... -[12:28:51] Connection established -[12:28:51] Initialize start: id=RequestId(I32(1)) -[12:28:52] Initialize finished, entering main loop -[12:30:26] Received message: Request(Request { id: RequestId(I32(2)), method: "shutdown", params: Null }) -[12:30:26] Request method: shutdown -[12:30:26] Unhandled request: shutdown From 99d28ba738bd3be2aa41ccded0825328d2571a79 Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Sat, 29 Nov 2025 15:30:48 +0545 Subject: [PATCH 27/50] Refactor: downcasting --- src/main.rs | 53 +++++++++++++++++++++++++++++--------------------- test-value.asm | 3 +++ 2 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 test-value.asm diff --git a/src/main.rs b/src/main.rs index 447a4f3..4809911 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,10 +6,10 @@ mod server; // use frontend::token::{Token, TokenType,Location}; // use frontend::utils::files::get_source_buffer; -use lsp_server::{Connection, Message, Notification, Request, Response}; +use lsp_server::{Connection, ExtractError, Message, Notification, Request, RequestId, Response}; use lsp_types::{ - ClientCapabilities, CompletionItem, CompletionOptions, CompletionResponse, InitializeParams, - ServerCapabilities, + ClientCapabilities, CompletionItem, CompletionOptions, CompletionResponse, Hover, HoverOptions, + HoverProviderCapability, InitializeParams, ServerCapabilities, request::Completion, }; use std::error::Error; @@ -35,16 +35,14 @@ fn main() -> Result<(), Box> { connection.initialize_finish(id, initialize_data)?; for msg in &connection.receiver { - match &msg { + match msg { Message::Request(req) => { - match req { - Request { method, .. } if *method == String::from("Close") => { - eprintln!("Close called!"); - } - Request { method, .. } - if *method == String::from("textDocument/completion") => - { - eprintln!("Close called!"); + if connection.handle_shutdown(&req)? { + return Ok(()); + } + eprintln!("got request: {:?}", req); + let req = match cast::(req) { + Ok((id, params)) => { let sample_responses = vec![ CompletionItem::new_simple( "MOV".to_string(), @@ -56,23 +54,26 @@ fn main() -> Result<(), Box> { ), CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), ]; - let resp = Response::new_ok( - req.id.clone(), - CompletionResponse::Array(sample_responses), - ); + let result = CompletionResponse::Array(sample_responses); + let result = serde_json::to_value(&result).unwrap(); + let resp = Response { + id, + result: Some(result), + error: None, + }; connection.sender.send(Message::Response(resp))?; + continue; } - e => { - eprintln!("unimplemented {:?}", e) - } - } - eprintln!("request: {:?}", req); + Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + Err(ExtractError::MethodMismatch(req)) => req, + }; + eprintln!("request not handled: {:?}", req); } Message::Response(rs) => { eprintln!("response: {:?}", rs); } Message::Notification(n) => { - match n { + match &n { Notification { method, .. } if *method == String::from("textDocument/didSave") => { @@ -113,3 +114,11 @@ fn main() -> Result<(), Box> { // } // } } + +fn cast(req: Request) -> Result<(RequestId, R::Params), ExtractError> +where + R: lsp_types::request::Request, + R::Params: serde::de::DeserializeOwned, +{ + req.extract(R::METHOD) +} diff --git a/test-value.asm b/test-value.asm new file mode 100644 index 0000000..fe11251 --- /dev/null +++ b/test-value.asm @@ -0,0 +1,3 @@ +ADD A,B +MOV A,B +SUB A,B From 1fd70e29b225f5a23141d922e7de7666452eb3e0 Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Sat, 29 Nov 2025 15:52:34 +0545 Subject: [PATCH 28/50] feat: implemented dummy hover request --- src/main.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 4809911..38c841a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ mod server; use lsp_server::{Connection, ExtractError, Message, Notification, Request, RequestId, Response}; use lsp_types::{ - ClientCapabilities, CompletionItem, CompletionOptions, CompletionResponse, Hover, HoverOptions, + ClientCapabilities, CompletionItem, CompletionOptions, CompletionResponse, HoverOptions, HoverProviderCapability, InitializeParams, ServerCapabilities, request::Completion, }; use std::error::Error; @@ -24,6 +24,7 @@ fn main() -> Result<(), Box> { let mut server_capabilities = ServerCapabilities::default(); server_capabilities.completion_provider = Some(CompletionOptions::default()); + server_capabilities.hover_provider = Some(HoverProviderCapability::Simple(true)); let initialize_data = serde_json::json!({ "capabilities": server_capabilities, @@ -43,6 +44,7 @@ fn main() -> Result<(), Box> { eprintln!("got request: {:?}", req); let req = match cast::(req) { Ok((id, params)) => { + eprintln!("got completion request #{}: {:?}", id, params); let sample_responses = vec![ CompletionItem::new_simple( "MOV".to_string(), @@ -67,6 +69,29 @@ fn main() -> Result<(), Box> { Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), Err(ExtractError::MethodMismatch(req)) => req, }; + let req = match cast::(req) { + Ok((id, params)) => { + eprintln!("hovr request {}: {:?}", id, params); + + let hover_result = lsp_types::Hover { + contents: lsp_types::HoverContents::Scalar( + lsp_types::MarkedString::String("dummy hover info".to_string()), + ), + range: None, + }; + + let result = serde_json::to_value(&hover_result).unwrap(); + let resp = Response { + id, + result: Some(result), + error: None, + }; + connection.sender.send(Message::Response(resp))?; + continue; + } + Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + Err(ExtractError::MethodMismatch(req)) => req, + }; eprintln!("request not handled: {:?}", req); } Message::Response(rs) => { From 539177da16a0052acc638ce66bf4baef3a8e5fc9 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Mon, 1 Dec 2025 18:19:26 +0545 Subject: [PATCH 29/50] add: builder scaffold for lsp85 --- Cargo.toml | 1 + grammar.txt | 21 --------------------- src/server/mod.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 21 deletions(-) delete mode 100644 grammar.txt diff --git a/Cargo.toml b/Cargo.toml index d25331d..1e310ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] lsp-server = "0.7.9" lsp-types = "0.97.0" +serde_json = "1.0.145" diff --git a/grammar.txt b/grammar.txt deleted file mode 100644 index 38b3294..0000000 --- a/grammar.txt +++ /dev/null @@ -1,21 +0,0 @@ - -OPCODE : ADD - |... - -REGISTER : A - | B - | C - | D - | E - | H - | L - | SP - | PSW - - : OPCODE - : REGISTER | NUM_LITERAL | e - : , REGISTER | , NUM_LITERAL | e - -ADD A B - -ADD REGISTER REGISTER diff --git a/src/server/mod.rs b/src/server/mod.rs index e69de29..5360663 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -0,0 +1,46 @@ +use lsp_server::{Connection,Message,Notification,Request,IoThreads}; +use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities,CompletionOptions}; +use std::error::{Error}; + + +pub struct lsp85{ + conn: Option, + io_threads: Option, + client_cap: Option, + server_cap: Option, +} + + +// builder methods +impl lsp85{ + pub fn builder()->Self{ + return Self{ + conn:None, + io_threads:None, + client_cap:None, + server_cap:None, + } + } + + pub fn stdio(mut self)-> Self{ + let (conn,io_threads) = Connection::stdio(); + + self.conn = Some(conn); + self.io_threads = Some(io_threads); + self.populate_client_cap(); + + self + } + + pub fn populate_client_cap(&mut self){ + let (id,params) = self.conn.as_ref().unwrap() + .initialize_start() + .expect("[ERROR] Failed to initialize server!"); + + let init_params: InitializeParams = serde_json::from_value(params).expect("[[ERROR] Failed to parse initialization params!"); + self.client_cap = Some(init_params.capabilities); + } + +} + + From c28ff3014cf772ea1bd5663c4270aa52fd5dafd9 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Thu, 4 Dec 2025 10:24:25 +0545 Subject: [PATCH 30/50] refactor: replaced existing structure with builder lsp --- src/main.rs | 37 ++++++++-------------- src/server/mod.rs | 81 +++++++++++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 52 deletions(-) diff --git a/src/main.rs b/src/main.rs index 38c841a..790c9c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,34 +11,23 @@ use lsp_types::{ ClientCapabilities, CompletionItem, CompletionOptions, CompletionResponse, HoverOptions, HoverProviderCapability, InitializeParams, ServerCapabilities, request::Completion, }; +use server::{lsp85}; use std::error::Error; fn main() -> Result<(), Box> { - let (connection, io_threads) = Connection::stdio(); - let (id, params) = connection.initialize_start()?; - eprintln!("Connection initialized!"); + let lsp = lsp85::build() + .stdio() + .enable_hover() + .initialize() + .unwrap(); - let init_params: InitializeParams = serde_json::from_value(params).unwrap(); - let client_capabilities: ClientCapabilities = init_params.capabilities; - let mut server_capabilities = ServerCapabilities::default(); - - server_capabilities.completion_provider = Some(CompletionOptions::default()); - server_capabilities.hover_provider = Some(HoverProviderCapability::Simple(true)); - - let initialize_data = serde_json::json!({ - "capabilities": server_capabilities, - "serverInfo": { - "name":"lsp85", - "version":"0.1", - } - }); - connection.initialize_finish(id, initialize_data)?; - - for msg in &connection.receiver { + for msg in &lsp.conn.as_ref().unwrap().receiver { + eprintln!("Message incoming: {:?}",msg); match msg { Message::Request(req) => { - if connection.handle_shutdown(&req)? { + if lsp.conn.as_ref().unwrap().handle_shutdown(&req)? { + eprintln!("shutting down!"); return Ok(()); } eprintln!("got request: {:?}", req); @@ -63,7 +52,7 @@ fn main() -> Result<(), Box> { result: Some(result), error: None, }; - connection.sender.send(Message::Response(resp))?; + lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; continue; } Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), @@ -86,7 +75,7 @@ fn main() -> Result<(), Box> { result: Some(result), error: None, }; - connection.sender.send(Message::Response(resp))?; + lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; continue; } Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), @@ -113,7 +102,7 @@ fn main() -> Result<(), Box> { } } - io_threads.join()?; + lsp.io_threads.unwrap().join()?; Ok(()) // if let Some(source) = get_source_buffer("test_value.asm") { diff --git a/src/server/mod.rs b/src/server/mod.rs index 5360663..b67d431 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,46 +1,71 @@ -use lsp_server::{Connection,Message,Notification,Request,IoThreads}; -use lsp_types::{InitializeParams,ClientCapabilities,ServerCapabilities,CompletionOptions}; -use std::error::{Error}; +use lsp_server::{Connection, IoThreads, Message, Notification, Request, RequestId}; +use lsp_types::{ + ClientCapabilities, CompletionOptions, HoverProviderCapability, InitializeParams, + ServerCapabilities, +}; +use std::error::Error; +use std::rc::Rc; - -pub struct lsp85{ - conn: Option, - io_threads: Option, - client_cap: Option, - server_cap: Option, +pub struct lsp85 { + id: Option, + pub conn: Option, + pub io_threads: Option, + client_cap: Option, + server_cap: Option, } - -// builder methods -impl lsp85{ - pub fn builder()->Self{ - return Self{ - conn:None, - io_threads:None, - client_cap:None, - server_cap:None, - } +// builder methods +impl lsp85 { + pub fn build() -> Self { + return Self { + id: None, + conn: None, + io_threads: None, + client_cap: None, + server_cap: Some(ServerCapabilities::default()), + }; } - pub fn stdio(mut self)-> Self{ - let (conn,io_threads) = Connection::stdio(); + pub fn stdio(mut self) -> Self { + let (conn, io_threads) = Connection::stdio(); self.conn = Some(conn); self.io_threads = Some(io_threads); self.populate_client_cap(); - self - } + self + } - pub fn populate_client_cap(&mut self){ - let (id,params) = self.conn.as_ref().unwrap() + fn populate_client_cap(&mut self) { + let (id, params) = self + .conn + .as_ref() + .expect("[ERROR] Connection not initialized!") .initialize_start() .expect("[ERROR] Failed to initialize server!"); - let init_params: InitializeParams = serde_json::from_value(params).expect("[[ERROR] Failed to parse initialization params!"); + self.id = Some(id); + + let init_params: InitializeParams = serde_json::from_value(params) + .expect("[[ERROR] Failed to parse initialization params!"); self.client_cap = Some(init_params.capabilities); } + pub fn enable_hover(mut self) -> Self { + self.server_cap + .as_mut() + .expect("[ERROR] Expected existing server_cap!") + .hover_provider = Some(HoverProviderCapability::Simple(true)); + self + } + pub fn initialize(self) -> Result> { + self.conn + .as_ref() + .expect("[ERROR] Expected populated connection!") + .initialize_finish( + self.id.as_ref().expect("Expected populated id!").clone(), + serde_json::to_value(&self.server_cap)?, + )?; + Ok(self) + } } - - From a379e35052365c17307367e7d8d6b5ca44683e29 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Thu, 4 Dec 2025 10:37:17 +0545 Subject: [PATCH 31/50] feat: add and fix for completion options --- src/main.rs | 1 + src/server/mod.rs | 19 ++++++++++++++++++- test-value.asm | 1 - 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 790c9c0..390c3f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ fn main() -> Result<(), Box> { let lsp = lsp85::build() .stdio() .enable_hover() + .enable_completion() .initialize() .unwrap(); diff --git a/src/server/mod.rs b/src/server/mod.rs index b67d431..4f04358 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -50,6 +50,14 @@ impl lsp85 { .expect("[[ERROR] Failed to parse initialization params!"); self.client_cap = Some(init_params.capabilities); } + pub fn enable_completion(mut self)->Self{ + self.server_cap + .as_mut() + .expect("[ERROR] Expected existing server_cap!") + .completion_provider = Some(CompletionOptions::default()); + self + } + pub fn enable_hover(mut self) -> Self { self.server_cap .as_mut() @@ -59,12 +67,21 @@ impl lsp85 { } pub fn initialize(self) -> Result> { + + let initialize_data = serde_json::json!({ + "capabilities": self.server_cap, + "serverInfo": { + "name":"lsp85", + "version":"0.1", + } + }); + self.conn .as_ref() .expect("[ERROR] Expected populated connection!") .initialize_finish( self.id.as_ref().expect("Expected populated id!").clone(), - serde_json::to_value(&self.server_cap)?, + initialize_data, )?; Ok(self) } diff --git a/test-value.asm b/test-value.asm index fe11251..b6cfcc0 100644 --- a/test-value.asm +++ b/test-value.asm @@ -1,3 +1,2 @@ ADD A,B -MOV A,B SUB A,B From 079d2ef4966938d0df750448b2f4335d626afd22 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 5 Dec 2025 14:46:17 +0545 Subject: [PATCH 32/50] feat: added macro for handler routing lsp --- src/main.rs | 21 +++++++++++++++------ src/server/handlers.rs | 23 +++++++++++++++++++++++ src/server/mod.rs | 1 + src/server/routers.rs | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 src/server/handlers.rs create mode 100644 src/server/routers.rs diff --git a/src/main.rs b/src/main.rs index 390c3f9..de4e624 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,10 +6,10 @@ mod server; // use frontend::token::{Token, TokenType,Location}; // use frontend::utils::files::get_source_buffer; -use lsp_server::{Connection, ExtractError, Message, Notification, Request, RequestId, Response}; +use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; use lsp_types::{ - ClientCapabilities, CompletionItem, CompletionOptions, CompletionResponse, HoverOptions, - HoverProviderCapability, InitializeParams, ServerCapabilities, request::Completion, + CompletionItem, CompletionResponse, + request::Completion, }; use server::{lsp85}; use std::error::Error; @@ -20,9 +20,9 @@ fn main() -> Result<(), Box> { .stdio() .enable_hover() .enable_completion() - .initialize() - .unwrap(); + .initialize(); + if let Ok(lsp) = lsp{ for msg in &lsp.conn.as_ref().unwrap().receiver { eprintln!("Message incoming: {:?}",msg); match msg { @@ -32,6 +32,9 @@ fn main() -> Result<(), Box> { return Ok(()); } eprintln!("got request: {:?}", req); + + + let req = match cast::(req) { Ok((id, params)) => { eprintln!("got completion request #{}: {:?}", id, params); @@ -102,8 +105,14 @@ fn main() -> Result<(), Box> { } } } - lsp.io_threads.unwrap().join()?; + + }else if let Err(e) = lsp{ + eprintln!("{:?}",e); + return Err(e); + } + + Ok(()) // if let Some(source) = get_source_buffer("test_value.asm") { diff --git a/src/server/handlers.rs b/src/server/handlers.rs new file mode 100644 index 0000000..ebdc4f3 --- /dev/null +++ b/src/server/handlers.rs @@ -0,0 +1,23 @@ +use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; +use lsp_types::{ + CompletionItem, CompletionResponse, + request::Completion, +}; + +pub fn completion_handler(id,params)->T + where T:CompletionResponse::Array{ + eprintln!("got completion request #{}: {:?}", id, params); + let sample_responses = vec![ + CompletionItem::new_simple( + "MOV".to_string(), + "Move instruction".to_string(), + ), + CompletionItem::new_simple( + "SUB".to_string(), + "Subtract instruction".to_string(), + ), + CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), + ]; + let result = CompletionResponse::Array(sample_responses); + return result; +} diff --git a/src/server/mod.rs b/src/server/mod.rs index 4f04358..671aa01 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,3 +1,4 @@ +pub mod handlers; use lsp_server::{Connection, IoThreads, Message, Notification, Request, RequestId}; use lsp_types::{ ClientCapabilities, CompletionOptions, HoverProviderCapability, InitializeParams, diff --git a/src/server/routers.rs b/src/server/routers.rs new file mode 100644 index 0000000..816a51c --- /dev/null +++ b/src/server/routers.rs @@ -0,0 +1,39 @@ +#[macro_export] +macro_rules! lsp_router{ + ( + $req:ident,$state:ident,$conn:ident, + { + $(($method:ident)=>$handler:ident),* $(,)? // optional comma at last ^_^ + } + ) =>{{ + + let mut __req = $req; + + $( + __req = match lsp_server::cast::<$method>(__req){ + Ok((id,params))=>{ + let result = $handler(&mut state,params); + + let result = serde_json::to_value(&result).unwrap(); + + let resp = lsp_server::Response { + id, + result: Some(result), + error: None, + } + $conn.as_ref().unwrap().sender().send( + lsp_server::Message::Response(resp) + ).unwrap(); + + continue; + }, + Err(lsp_server::ExtractError::JsonError { error, .. }) => { + panic!("Invalid params for {}: {:?}", stringify!($method), error); + }, + + Err(lsp_server::ExtractError::MethodMismatch(req)) => req, + + } + )* + }} +} From 9a23fd91ee7ad8477accf6057196e6aed60f9c45 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 5 Dec 2025 15:47:56 +0545 Subject: [PATCH 33/50] fix: fixed broken macro rules --- src/main.rs | 108 +++++++++++++++++++++-------------------- src/server/handlers.rs | 7 +-- src/server/mod.rs | 3 ++ src/server/routers.rs | 53 ++++++++------------ test-value.asm | 2 - 5 files changed, 81 insertions(+), 92 deletions(-) diff --git a/src/main.rs b/src/main.rs index de4e624..e7b407d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use lsp_types::{ CompletionItem, CompletionResponse, request::Completion, }; -use server::{lsp85}; +use server::{lsp85,routers,handlers}; use std::error::Error; fn main() -> Result<(), Box> { @@ -35,57 +35,59 @@ fn main() -> Result<(), Box> { - let req = match cast::(req) { - Ok((id, params)) => { - eprintln!("got completion request #{}: {:?}", id, params); - let sample_responses = vec![ - CompletionItem::new_simple( - "MOV".to_string(), - "Move instruction".to_string(), - ), - CompletionItem::new_simple( - "SUB".to_string(), - "Subtract instruction".to_string(), - ), - CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), - ]; - let result = CompletionResponse::Array(sample_responses); - let result = serde_json::to_value(&result).unwrap(); - let resp = Response { - id, - result: Some(result), - error: None, - }; - lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; - continue; - } - Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), - Err(ExtractError::MethodMismatch(req)) => req, - }; - let req = match cast::(req) { - Ok((id, params)) => { - eprintln!("hovr request {}: {:?}", id, params); - - let hover_result = lsp_types::Hover { - contents: lsp_types::HoverContents::Scalar( - lsp_types::MarkedString::String("dummy hover info".to_string()), - ), - range: None, - }; - - let result = serde_json::to_value(&hover_result).unwrap(); - let resp = Response { - id, - result: Some(result), - error: None, - }; - lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; - continue; - } - Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), - Err(ExtractError::MethodMismatch(req)) => req, - }; - eprintln!("request not handled: {:?}", req); + // let req = match cast::(req) { + // Ok((id, params)) => { + // eprintln!("got completion request #{}: {:?}", id, params); + // let sample_responses = vec![ + // CompletionItem::new_simple( + // "MOV".to_string(), + // "Move instruction".to_string(), + // ), + // CompletionItem::new_simple( + // "SUB".to_string(), + // "Subtract instruction".to_string(), + // ), + // CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), + // ]; + // let result = CompletionResponse::Array(sample_responses); + // let result = serde_json::to_value(&result).unwrap(); + // let resp = Response { + // id, + // result: Some(result), + // error: None, + // }; + // lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; + // continue; + // } + // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + // Err(ExtractError::MethodMismatch(req)) => req, + // }; + lsp_router!(req,lsp,{ + Completion=>handlers::completion_handler, + }); + // let req = match cast::(req) { + // Ok((id, params)) => { + // eprintln!("hovr request {}: {:?}", id, params); + + // let hover_result = lsp_types::Hover { + // contents: lsp_types::HoverContents::Scalar( + // lsp_types::MarkedString::String("dummy hover info".to_string()), + // ), + // range: None, + // }; + + // let result = serde_json::to_value(&hover_result).unwrap(); + // let resp = Response { + // id, + // result: Some(result), + // error: None, + // }; + // lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; + // continue; + // } + // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + // Err(ExtractError::MethodMismatch(req)) => req, + // }; } Message::Response(rs) => { eprintln!("response: {:?}", rs); @@ -98,7 +100,7 @@ fn main() -> Result<(), Box> { eprintln!("File saved!"); } e => { - eprintln!("unimplemented {:?}", e) + eprintln!("unimplemented {:?}", e); } } eprintln!("notification: {:?}", n); diff --git a/src/server/handlers.rs b/src/server/handlers.rs index ebdc4f3..c79112e 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -1,11 +1,11 @@ use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; +use serde_json; use lsp_types::{ CompletionItem, CompletionResponse, - request::Completion, + CompletionParams }; -pub fn completion_handler(id,params)->T - where T:CompletionResponse::Array{ +pub fn completion_handler(id:&RequestId ,params:CompletionParams)->serde_json::Value{ eprintln!("got completion request #{}: {:?}", id, params); let sample_responses = vec![ CompletionItem::new_simple( @@ -19,5 +19,6 @@ pub fn completion_handler(id,params)->T CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), ]; let result = CompletionResponse::Array(sample_responses); + let result = serde_json::to_value(&result).unwrap(); return result; } diff --git a/src/server/mod.rs b/src/server/mod.rs index 671aa01..cdceafe 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,4 +1,7 @@ pub mod handlers; +pub mod routers; + + use lsp_server::{Connection, IoThreads, Message, Notification, Request, RequestId}; use lsp_types::{ ClientCapabilities, CompletionOptions, HoverProviderCapability, InitializeParams, diff --git a/src/server/routers.rs b/src/server/routers.rs index 816a51c..adffe16 100644 --- a/src/server/routers.rs +++ b/src/server/routers.rs @@ -1,39 +1,24 @@ #[macro_export] -macro_rules! lsp_router{ +macro_rules! lsp_router { ( - $req:ident,$state:ident,$conn:ident, - { - $(($method:ident)=>$handler:ident),* $(,)? // optional comma at last ^_^ + $req:ident, $state:ident, { + $( $method:ty => $handler:path ),* $(,)? } - ) =>{{ - - let mut __req = $req; - - $( - __req = match lsp_server::cast::<$method>(__req){ - Ok((id,params))=>{ - let result = $handler(&mut state,params); - - let result = serde_json::to_value(&result).unwrap(); - - let resp = lsp_server::Response { - id, - result: Some(result), - error: None, + ) => {{ +$( + let __req = match cast::<$method>($req) { + Ok((id, params)) => { + let resp = Response { + result: Some($handler(&id,params)), + id, + error: None, + }; + $state.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; + return Ok(()) } - $conn.as_ref().unwrap().sender().send( - lsp_server::Message::Response(resp) - ).unwrap(); - - continue; - }, - Err(lsp_server::ExtractError::JsonError { error, .. }) => { - panic!("Invalid params for {}: {:?}", stringify!($method), error); - }, - - Err(lsp_server::ExtractError::MethodMismatch(req)) => req, - - } - )* - }} + Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + Err(ExtractError::MethodMismatch(req)) => req, + }; +)* + }}; } diff --git a/test-value.asm b/test-value.asm index b6cfcc0..e69de29 100644 --- a/test-value.asm +++ b/test-value.asm @@ -1,2 +0,0 @@ -ADD A,B -SUB A,B From 7d90b7ff3c0b2732161b52e6b4fba6e815eb6617 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 5 Dec 2025 16:22:05 +0545 Subject: [PATCH 34/50] add: trial-instructions for completion --- src/main.rs | 20 ++---------------- src/server/handlers.rs | 48 +++++++++++++++++++++++++++++++++++++----- src/server/routers.rs | 6 +++--- 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/main.rs b/src/main.rs index e7b407d..9397006 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ mod server; use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; use lsp_types::{ CompletionItem, CompletionResponse, - request::Completion, + request::{Completion,HoverRequest}, }; use server::{lsp85,routers,handlers}; use std::error::Error; @@ -64,26 +64,10 @@ fn main() -> Result<(), Box> { // }; lsp_router!(req,lsp,{ Completion=>handlers::completion_handler, + HoverRequest=>handlers::hover_handler, }); // let req = match cast::(req) { // Ok((id, params)) => { - // eprintln!("hovr request {}: {:?}", id, params); - - // let hover_result = lsp_types::Hover { - // contents: lsp_types::HoverContents::Scalar( - // lsp_types::MarkedString::String("dummy hover info".to_string()), - // ), - // range: None, - // }; - - // let result = serde_json::to_value(&hover_result).unwrap(); - // let resp = Response { - // id, - // result: Some(result), - // error: None, - // }; - // lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; - // continue; // } // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), // Err(ExtractError::MethodMismatch(req)) => req, diff --git a/src/server/handlers.rs b/src/server/handlers.rs index c79112e..60dca02 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -2,23 +2,61 @@ use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Respon use serde_json; use lsp_types::{ CompletionItem, CompletionResponse, - CompletionParams + CompletionParams, + HoverParams, + }; pub fn completion_handler(id:&RequestId ,params:CompletionParams)->serde_json::Value{ eprintln!("got completion request #{}: {:?}", id, params); - let sample_responses = vec![ + let responses = vec![ CompletionItem::new_simple( "MOV".to_string(), - "Move instruction".to_string(), + "This instruction copies the content of the source register into destination register.".to_string(), + ), + CompletionItem::new_simple( + "MVI".to_string(), + "The 8-bit data is stored in the destination register of memory.".to_string(), + ), + CompletionItem::new_simple( + "LDA".to_string(), + "The contents of a memory location, specified by a 16-bit address in the operand, are copied to the accumulator.".to_string(), + ), + CompletionItem::new_simple( + "LDAX".to_string(), + "The contents of the designated register pair point to a memory location. This instruction copies the contents of that memory location into the accumulator.".to_string(), + ), + CompletionItem::new_simple( + "LXI".to_string(), + "The instruction loads 16-bit data in the register pair designated in the operand.".to_string(), + ), + CompletionItem::new_simple( + "LHLD".to_string(), + "The instruction copies the contents of the memory location pointed out by the 16-bit address into the register L and copies the contents of the next memory location into register H. The contents of the source memory are not altered.".to_string(), ), CompletionItem::new_simple( "SUB".to_string(), "Subtract instruction".to_string(), ), - CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), + CompletionItem::new_simple( + "ADD".to_string(), + "Add values".to_string(), + ), ]; - let result = CompletionResponse::Array(sample_responses); + let result = CompletionResponse::Array(responses); let result = serde_json::to_value(&result).unwrap(); return result; } +pub fn hover_handler(id:&RequestId ,params:HoverParams)->serde_json::Value{ + eprintln!("hovr request {}: {:?}", id, params); + + let hover_result = lsp_types::Hover { + contents: lsp_types::HoverContents::Scalar( + lsp_types::MarkedString::String("dummy hover info".to_string()), + ), + range: None, + }; + + let result = serde_json::to_value(&hover_result).unwrap(); + return result; +} diff --git a/src/server/routers.rs b/src/server/routers.rs index adffe16..d0561ff 100644 --- a/src/server/routers.rs +++ b/src/server/routers.rs @@ -6,7 +6,7 @@ macro_rules! lsp_router { } ) => {{ $( - let __req = match cast::<$method>($req) { + let req = match cast::<$method>($req.clone()) { Ok((id, params)) => { let resp = Response { result: Some($handler(&id,params)), @@ -14,8 +14,8 @@ $( error: None, }; $state.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; - return Ok(()) - } + continue; + }, Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), Err(ExtractError::MethodMismatch(req)) => req, }; From 4f759c605c64c52b242f66f0b3837547cf5c3326 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 5 Dec 2025 16:52:14 +0545 Subject: [PATCH 35/50] refactor: description of completions --- src/server/handlers.rs | 122 +++++++++++++++++++++++++++++------------ test-value.asm | 1 + 2 files changed, 88 insertions(+), 35 deletions(-) diff --git a/src/server/handlers.rs b/src/server/handlers.rs index 60dca02..346d88b 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -4,45 +4,97 @@ use lsp_types::{ CompletionItem, CompletionResponse, CompletionParams, HoverParams, - + Documentation, + MarkupContent, + MarkupKind, }; +use lsp_types::CompletionItemKind; pub fn completion_handler(id:&RequestId ,params:CompletionParams)->serde_json::Value{ eprintln!("got completion request #{}: {:?}", id, params); - let responses = vec![ - CompletionItem::new_simple( - "MOV".to_string(), - "This instruction copies the content of the source register into destination register.".to_string(), - ), - CompletionItem::new_simple( - "MVI".to_string(), - "The 8-bit data is stored in the destination register of memory.".to_string(), - ), - CompletionItem::new_simple( - "LDA".to_string(), - "The contents of a memory location, specified by a 16-bit address in the operand, are copied to the accumulator.".to_string(), - ), - CompletionItem::new_simple( - "LDAX".to_string(), - "The contents of the designated register pair point to a memory location. This instruction copies the contents of that memory location into the accumulator.".to_string(), - ), - CompletionItem::new_simple( - "LXI".to_string(), - "The instruction loads 16-bit data in the register pair designated in the operand.".to_string(), - ), - CompletionItem::new_simple( - "LHLD".to_string(), - "The instruction copies the contents of the memory location pointed out by the 16-bit address into the register L and copies the contents of the next memory location into register H. The contents of the source memory are not altered.".to_string(), - ), - CompletionItem::new_simple( - "SUB".to_string(), - "Subtract instruction".to_string(), - ), - CompletionItem::new_simple( - "ADD".to_string(), - "Add values".to_string(), - ), - ]; + let responses = vec![ + CompletionItem { + label: "MOV".to_string(), + detail: Some("MOV - Move data between registers".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "`MOV` instruction **copies** the content of the **source register** into **destination register**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "MVI".to_string(), + detail: Some("MVI - Move immediate data".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The **8-bit data** is stored in the **destination register** of **memory**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "LDA".to_string(), + detail: Some("LDA - Load accumulator direct".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The contents of a **memory location**, specified by a **16-bit address** in the operand, are copied to the **accumulator**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "LDAX".to_string(), + detail: Some("LDAX - Load accumulator indirect".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The contents of the **designated register pair** point to a **memory location**. This instruction **copies** the contents of that memory location into the **accumulator**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "LXI".to_string(), + detail: Some("LXI - Load register pair immediate".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The instruction **loads 16-bit data** in the **register pair** designated in the operand.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "LHLD".to_string(), + detail: Some("LHLD - Load H and L registers direct".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The instruction **copies** the contents of the **memory location** pointed out by the **16-bit address** into **register L** and copies the contents of the **next memory location** into **register H**. The contents of the **source memory** are not altered.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "SUB".to_string(), + detail: Some("SUB - Subtract".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "**Subtract** instruction".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "ADD".to_string(), + detail: Some("ADD - Add".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "**Add** values".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + ]; + let result = CompletionResponse::Array(responses); let result = serde_json::to_value(&result).unwrap(); return result; diff --git a/test-value.asm b/test-value.asm index e69de29..8b13789 100644 --- a/test-value.asm +++ b/test-value.asm @@ -0,0 +1 @@ + From f3cc41418b039e2edfcd8e2abc99e0e951a66251 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 5 Dec 2025 17:05:02 +0545 Subject: [PATCH 36/50] chore: rustfmt --- src/server/handlers.rs | 48 +++++++++++++++++++----------------------- src/server/mod.rs | 4 +--- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/server/handlers.rs b/src/server/handlers.rs index 346d88b..41d798f 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -1,18 +1,14 @@ use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; -use serde_json; +use lsp_types::CompletionItemKind; use lsp_types::{ - CompletionItem, CompletionResponse, - CompletionParams, - HoverParams, - Documentation, - MarkupContent, - MarkupKind, + CompletionItem, CompletionParams, CompletionResponse, Documentation, HoverParams, + MarkupContent, MarkupKind, }; -use lsp_types::CompletionItemKind; +use serde_json; -pub fn completion_handler(id:&RequestId ,params:CompletionParams)->serde_json::Value{ - eprintln!("got completion request #{}: {:?}", id, params); - let responses = vec![ +pub fn completion_handler(id: &RequestId, params: CompletionParams) -> serde_json::Value { + eprintln!("got completion request #{}: {:?}", id, params); + let responses = vec![ CompletionItem { label: "MOV".to_string(), detail: Some("MOV - Move data between registers".to_string()), @@ -95,20 +91,20 @@ pub fn completion_handler(id:&RequestId ,params:CompletionParams)->serde_json::V }, ]; - let result = CompletionResponse::Array(responses); - let result = serde_json::to_value(&result).unwrap(); - return result; -} -pub fn hover_handler(id:&RequestId ,params:HoverParams)->serde_json::Value{ - eprintln!("hovr request {}: {:?}", id, params); + let result = CompletionResponse::Array(responses); + let result = serde_json::to_value(&result).unwrap(); + return result; +} +pub fn hover_handler(id: &RequestId, params: HoverParams) -> serde_json::Value { + eprintln!("hovr request {}: {:?}", id, params); - let hover_result = lsp_types::Hover { - contents: lsp_types::HoverContents::Scalar( - lsp_types::MarkedString::String("dummy hover info".to_string()), - ), - range: None, - }; + let hover_result = lsp_types::Hover { + contents: lsp_types::HoverContents::Scalar(lsp_types::MarkedString::String( + "dummy hover info".to_string(), + )), + range: None, + }; - let result = serde_json::to_value(&hover_result).unwrap(); - return result; -} + let result = serde_json::to_value(&hover_result).unwrap(); + return result; +} diff --git a/src/server/mod.rs b/src/server/mod.rs index cdceafe..6cc74d4 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,7 +1,6 @@ pub mod handlers; pub mod routers; - use lsp_server::{Connection, IoThreads, Message, Notification, Request, RequestId}; use lsp_types::{ ClientCapabilities, CompletionOptions, HoverProviderCapability, InitializeParams, @@ -54,7 +53,7 @@ impl lsp85 { .expect("[[ERROR] Failed to parse initialization params!"); self.client_cap = Some(init_params.capabilities); } - pub fn enable_completion(mut self)->Self{ + pub fn enable_completion(mut self) -> Self { self.server_cap .as_mut() .expect("[ERROR] Expected existing server_cap!") @@ -71,7 +70,6 @@ impl lsp85 { } pub fn initialize(self) -> Result> { - let initialize_data = serde_json::json!({ "capabilities": self.server_cap, "serverInfo": { From 44c37c4d2f083592d6100373efbf4586bfa74eda Mon Sep 17 00:00:00 2001 From: shri-acha Date: Sat, 6 Dec 2025 09:36:23 +0545 Subject: [PATCH 37/50] refactor: got rid of unecessary clone --- src/frontend/lexer.rs | 42 ++++++------ src/frontend/parser.rs | 120 ++++++++++++++++++++--------------- src/frontend/token.rs | 4 +- src/main.rs | 141 ++++++++++++++++++++--------------------- src/server/routers.rs | 2 +- 5 files changed, 157 insertions(+), 152 deletions(-) diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 6934cff..32c7977 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -145,7 +145,7 @@ mod tests { #[test] fn imm_test() { let source = String::from("MVI A,05H\n"); - let mut l = Lexer::new(source,0); + let mut l = Lexer::new(source, 0); let mut tokens: Vec = vec![]; for token in l { tokens.push(token); @@ -157,27 +157,22 @@ mod tests { 3, TokenType::OPERATION, Location::new(0, 3), - "MVI".to_string()), - Token::new( - 1, - TokenType::REGISTER, - Location::new(0, 5), - "A".to_string()), + "MVI".to_string() + ), + Token::new(1, TokenType::REGISTER, Location::new(0, 5), "A".to_string()), Token::new( 1, TokenType::COMMA_DELIM, Location::new(0, 6), - ",".to_string()), + ",".to_string() + ), Token::new( 3, TokenType::IMM_VALUE, Location::new(0, 9), - "05H".to_string()), - Token::new( - 1, - TokenType::EOL, - Location::new(0, 10), - "\n".to_string()) + "05H".to_string() + ), + Token::new(1, TokenType::EOL, Location::new(0, 10), "\n".to_string()) ], tokens ); @@ -186,7 +181,7 @@ mod tests { #[test] fn reg_pair() { let source = String::from("MVI A,SP\n"); - let mut l = Lexer::new(source,0); + let mut l = Lexer::new(source, 0); let mut tokens: Vec = vec![]; for token in l { tokens.push(token); @@ -198,23 +193,22 @@ mod tests { 3, TokenType::OPERATION, Location::new(0, 3), - "MVI".to_string()), - Token::new( 1, TokenType::REGISTER, Location::new(0, 5), "A".to_string()), + "MVI".to_string() + ), + Token::new(1, TokenType::REGISTER, Location::new(0, 5), "A".to_string()), Token::new( 1, TokenType::COMMA_DELIM, Location::new(0, 6), - ",".to_string()), + ",".to_string() + ), Token::new( 2, TokenType::REGISTER, Location::new(0, 8), - "SP".to_string()), - Token::new( - 1, - TokenType::EOL, - Location::new(0, 9), - "\n".to_string()) + "SP".to_string() + ), + Token::new(1, TokenType::EOL, Location::new(0, 9), "\n".to_string()) ], tokens ); diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index 3df4ffc..f391155 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -14,115 +14,131 @@ impl Parser { } } -#[derive(Debug,PartialEq)] -pub struct Tree{ +#[derive(Debug, PartialEq)] +pub struct Tree { pub l_child: Option, pub r_child: Option, } impl Tree { - pub fn default()->Self{ - Self{ - l_child:None, - r_child:None, + pub fn default() -> Self { + Self { + l_child: None, + r_child: None, } } - pub fn new(l_child:Option,r_child: Option)->Self{ - Self{ - l_child, - r_child - } + pub fn new(l_child: Option, r_child: Option) -> Self { + Self { l_child, r_child } } } -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] pub struct Node { pub value: Token, - pub branch: Box + pub branch: Box, } -impl Node{ - pub fn new(tok_val: Token, branch: Box)->Self{ - Self{ +impl Node { + pub fn new(tok_val: Token, branch: Box) -> Self { + Self { value: tok_val, - branch + branch, } } } impl Parser { - pub fn parse_expression(&mut self)->Option{ - - if let Some(peeked_token) = self.tok_stream.peek(){ - println!("parse_expression() called! {:?}",peeked_token); + pub fn parse_expression(&mut self) -> Option { + if let Some(peeked_token) = self.tok_stream.peek() { + println!("parse_expression() called! {:?}", peeked_token); match peeked_token { - Token{tok_type: TokenType::OPERATION,..}=>{ + Token { + tok_type: TokenType::OPERATION, + .. + } => { return self.parse_operation(); - }, - Token{tok_type: TokenType::REGISTER, ..}=>{ + } + Token { + tok_type: TokenType::REGISTER, + .. + } => { println!("unexpected placement of register!"); return None; } - Token{tok_type: TokenType::EOF, ..}=>{ + Token { + tok_type: TokenType::EOF, + .. + } => { return None; } - _ =>{ + _ => { self.tok_stream.next(); return self.parse_expression(); } } - }else{ + } else { return None; } } - pub fn parse_operation(&mut self)->Option{ + pub fn parse_operation(&mut self) -> Option { let mut l_child: Node; - if let Some(peeked_token) = self.tok_stream.peek(){ - l_child = Node::new(peeked_token.clone(),Box::new(Tree::default())); - }else{ + if let Some(peeked_token) = self.tok_stream.peek() { + l_child = Node::new(peeked_token.clone(), Box::new(Tree::default())); + } else { return None; } self.tok_stream.next(); - if let Some(peeked_token) = self.tok_stream.peek(){ - match peeked_token{ - Token{ tok_type: TokenType::REGISTER, .. }=>{ + if let Some(peeked_token) = self.tok_stream.peek() { + match peeked_token { + Token { + tok_type: TokenType::REGISTER, + .. + } => { l_child.branch.l_child = self.parse_operand(); l_child.branch.r_child = self.parse_operand(); return Some(l_child); - }, - _=>{ + } + _ => { return Some(l_child); } } - }else{ + } else { return Some(l_child); } } - pub fn parse_operand(&mut self)->Option{ - + pub fn parse_operand(&mut self) -> Option { let mut l_child: Node; - if let Some(peeked_token) = self.tok_stream.peek(){ - match peeked_token{ - Token{tok_type: TokenType:: REGISTER, .. }=>{ + if let Some(peeked_token) = self.tok_stream.peek() { + match peeked_token { + Token { + tok_type: TokenType::REGISTER, + .. + } => { let token_buffer = peeked_token.clone(); self.tok_stream.next(); - return Some(Node::new(token_buffer,Box::new(Tree::default()))); - }, - Token{tok_type: TokenType:: COMMA_DELIM, .. }=>{ + return Some(Node::new(token_buffer, Box::new(Tree::default()))); + } + Token { + tok_type: TokenType::COMMA_DELIM, + .. + } => { self.tok_stream.next(); return self.parse_operand(); - }, - Token{tok_type: TokenType:: IMM_VALUE, .. }=>{ + } + Token { + tok_type: TokenType::IMM_VALUE, + .. + } => { let token_buffer = peeked_token.clone(); self.tok_stream.next(); - return Some(Node::new(token_buffer,Box::new(Tree::default()))); - }, - _ =>{ + return Some(Node::new(token_buffer, Box::new(Tree::default()))); + } + _ => { return None; } } - }else{ + } else { return None; - } + } } } diff --git a/src/frontend/token.rs b/src/frontend/token.rs index cada4bb..17d1f56 100644 --- a/src/frontend/token.rs +++ b/src/frontend/token.rs @@ -9,7 +9,7 @@ impl Location { } } -#[derive(Debug,Clone,PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct Token { pub tok_literal: String, pub tok_type: TokenType, @@ -38,7 +38,7 @@ impl Token { // INSTRUCTION // OPERATION REGISTER COMMA_DELIM REGISTER // -#[derive(Debug,Copy,Clone,PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub enum TokenType { OPERATION, IMM_VALUE, diff --git a/src/main.rs b/src/main.rs index 9397006..9e9ccc4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,97 +8,92 @@ mod server; use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; use lsp_types::{ + request::{Completion, HoverRequest}, CompletionItem, CompletionResponse, - request::{Completion,HoverRequest}, }; -use server::{lsp85,routers,handlers}; +use server::{handlers, lsp85, routers}; use std::error::Error; fn main() -> Result<(), Box> { - let lsp = lsp85::build() - .stdio() - .enable_hover() - .enable_completion() - .initialize(); - - if let Ok(lsp) = lsp{ - for msg in &lsp.conn.as_ref().unwrap().receiver { - eprintln!("Message incoming: {:?}",msg); - match msg { - Message::Request(req) => { - if lsp.conn.as_ref().unwrap().handle_shutdown(&req)? { - eprintln!("shutting down!"); - return Ok(()); - } - eprintln!("got request: {:?}", req); - + .stdio() + .enable_hover() + .enable_completion() + .initialize(); + if let Ok(lsp) = lsp { + for msg in &lsp.conn.as_ref().unwrap().receiver { + eprintln!("Message incoming: {:?}", msg); + match msg { + Message::Request(req) => { + if lsp.conn.as_ref().unwrap().handle_shutdown(&req)? { + eprintln!("shutting down!"); + return Ok(()); + } + eprintln!("got request: {:?}", req); - // let req = match cast::(req) { - // Ok((id, params)) => { - // eprintln!("got completion request #{}: {:?}", id, params); - // let sample_responses = vec![ - // CompletionItem::new_simple( - // "MOV".to_string(), - // "Move instruction".to_string(), - // ), - // CompletionItem::new_simple( - // "SUB".to_string(), - // "Subtract instruction".to_string(), - // ), - // CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), - // ]; - // let result = CompletionResponse::Array(sample_responses); - // let result = serde_json::to_value(&result).unwrap(); - // let resp = Response { - // id, - // result: Some(result), - // error: None, - // }; - // lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; - // continue; - // } - // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), - // Err(ExtractError::MethodMismatch(req)) => req, - // }; - lsp_router!(req,lsp,{ + // let req = match cast::(req) { + // Ok((id, params)) => { + // eprintln!("got completion request #{}: {:?}", id, params); + // let sample_responses = vec![ + // CompletionItem::new_simple( + // "MOV".to_string(), + // "Move instruction".to_string(), + // ), + // CompletionItem::new_simple( + // "SUB".to_string(), + // "Subtract instruction".to_string(), + // ), + // CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), + // ]; + // let result = CompletionResponse::Array(sample_responses); + // let result = serde_json::to_value(&result).unwrap(); + // let resp = Response { + // id, + // result: Some(result), + // error: None, + // }; + // lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; + // continue; + // } + // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + // Err(ExtractError::MethodMismatch(req)) => req, + // }; + lsp_router!(req,lsp,{ Completion=>handlers::completion_handler, HoverRequest=>handlers::hover_handler, }); - // let req = match cast::(req) { - // Ok((id, params)) => { - // } - // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), - // Err(ExtractError::MethodMismatch(req)) => req, - // }; - } - Message::Response(rs) => { - eprintln!("response: {:?}", rs); - } - Message::Notification(n) => { - match &n { - Notification { method, .. } - if *method == String::from("textDocument/didSave") => - { - eprintln!("File saved!"); - } - e => { - eprintln!("unimplemented {:?}", e); + // let req = match cast::(req) { + // Ok((id, params)) => { + // } + // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + // Err(ExtractError::MethodMismatch(req)) => req, + // }; + } + Message::Response(rs) => { + eprintln!("response: {:?}", rs); + } + Message::Notification(n) => { + match &n { + Notification { method, .. } + if *method == String::from("textDocument/didSave") => + { + eprintln!("File saved!"); + } + e => { + eprintln!("unimplemented {:?}", e); + } } + eprintln!("notification: {:?}", n); } - eprintln!("notification: {:?}", n); } } - } - lsp.io_threads.unwrap().join()?; - - }else if let Err(e) = lsp{ - eprintln!("{:?}",e); + lsp.io_threads.unwrap().join()?; + } else if let Err(e) = lsp { + eprintln!("{:?}", e); return Err(e); } - Ok(()) // if let Some(source) = get_source_buffer("test_value.asm") { diff --git a/src/server/routers.rs b/src/server/routers.rs index d0561ff..8639940 100644 --- a/src/server/routers.rs +++ b/src/server/routers.rs @@ -6,7 +6,7 @@ macro_rules! lsp_router { } ) => {{ $( - let req = match cast::<$method>($req.clone()) { + let $req = match cast::<$method>($req) { Ok((id, params)) => { let resp = Response { result: Some($handler(&id,params)), From 8bfa8bf8c9140ece730400cb57a6614f7be8aa0e Mon Sep 17 00:00:00 2001 From: Prabesh-Sharma Date: Sun, 7 Dec 2025 21:02:21 +0545 Subject: [PATCH 38/50] Refactor: error handling --- src/main.rs | 198 +++++++++++++++++++++++++++---------------------- test-value.asm | 1 - 2 files changed, 110 insertions(+), 89 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9e9ccc4..3309c61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,8 +8,8 @@ mod server; use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; use lsp_types::{ - request::{Completion, HoverRequest}, CompletionItem, CompletionResponse, + request::{Completion, HoverRequest}, }; use server::{handlers, lsp85, routers}; use std::error::Error; @@ -21,104 +21,126 @@ fn main() -> Result<(), Box> { .enable_completion() .initialize(); - if let Ok(lsp) = lsp { - for msg in &lsp.conn.as_ref().unwrap().receiver { - eprintln!("Message incoming: {:?}", msg); - match msg { - Message::Request(req) => { - if lsp.conn.as_ref().unwrap().handle_shutdown(&req)? { - eprintln!("shutting down!"); - return Ok(()); - } - eprintln!("got request: {:?}", req); + let lsp = match lsp { + Ok(lsp) => lsp, + Err(e) => { + eprintln!("init failed: {:?}", e); + return Err(e); + } + }; - // let req = match cast::(req) { - // Ok((id, params)) => { - // eprintln!("got completion request #{}: {:?}", id, params); - // let sample_responses = vec![ - // CompletionItem::new_simple( - // "MOV".to_string(), - // "Move instruction".to_string(), - // ), - // CompletionItem::new_simple( - // "SUB".to_string(), - // "Subtract instruction".to_string(), - // ), - // CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), - // ]; - // let result = CompletionResponse::Array(sample_responses); - // let result = serde_json::to_value(&result).unwrap(); - // let resp = Response { - // id, - // result: Some(result), - // error: None, - // }; - // lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; - // continue; - // } - // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), - // Err(ExtractError::MethodMismatch(req)) => req, - // }; - lsp_router!(req,lsp,{ - Completion=>handlers::completion_handler, - HoverRequest=>handlers::hover_handler, - }); - // let req = match cast::(req) { - // Ok((id, params)) => { - // } - // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), - // Err(ExtractError::MethodMismatch(req)) => req, - // }; - } - Message::Response(rs) => { - eprintln!("response: {:?}", rs); + let conn = match lsp.conn.as_ref() { + Some(conn) => conn, + None => { + eprintln!("no conn"); + return Err("no conn".into()); + } + }; + + for msg in &conn.receiver { + eprintln!("Message incoming: {:?}", msg); + match msg { + Message::Request(req) => { + let down = match conn.handle_shutdown(&req) { + Ok(true) => true, + Ok(false) => false, + Err(e) => { + eprintln!("error: {:?}", e); + false + } + }; + if down { + eprintln!("shutting down!"); + return Ok(()); } - Message::Notification(n) => { - match &n { - Notification { method, .. } - if *method == String::from("textDocument/didSave") => - { - eprintln!("File saved!"); - } - e => { - eprintln!("unimplemented {:?}", e); - } + eprintln!("got request: {:?}", req); + + // let req = match cast::(req) { + // Ok((id, params)) => { + // eprintln!("got completion request #{}: {:?}", id, params); + // let sample_responses = vec![ + // CompletionItem::new_simple( + // "MOV".to_string(), + // "Move instruction".to_string(), + // ), + // CompletionItem::new_simple( + // "SUB".to_string(), + // "Subtract instruction".to_string(), + // ), + // CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), + // ]; + // let result = CompletionResponse::Array(sample_responses); + // let result = serde_json::to_value(&result).unwrap(); + // let resp = Response { + // id, + // result: Some(result), + // error: None, + // }; + // lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; + // continue; + // } + // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + // Err(ExtractError::MethodMismatch(req)) => req, + // }; + lsp_router!(req,lsp,{ + Completion=>handlers::completion_handler, + HoverRequest=>handlers::hover_handler, + }); + // let req = match cast::(req) { + // Ok((id, params)) => { + // } + // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + // Err(ExtractError::MethodMismatch(req)) => req, + // }; + } + Message::Response(rs) => { + eprintln!("response: {:?}", rs); + } + Message::Notification(n) => { + match &n { + Notification { method, .. } + if *method == String::from("textDocument/didSave") => + { + eprintln!("File saved!"); + } + e => { + eprintln!("unimplemented {:?}", e); } - eprintln!("notification: {:?}", n); } + eprintln!("notification: {:?}", n); } } - lsp.io_threads.unwrap().join()?; - } else if let Err(e) = lsp { - eprintln!("{:?}", e); - return Err(e); } - Ok(()) + if let Some(io_threads) = lsp.io_threads { + if let Err(e) = io_threads.join() { + eprintln!("Error joining IO threads: {:?}", e); + } + } - // if let Some(source) = get_source_buffer("test_value.asm") { - // // buffered reading - // let mut ast_list: Vec> = vec![]; - // for (line_no, read_buf) in source { - // if let Ok(read_buf) = read_buf { - // let mut l = Lexer::new(read_buf, line_no); - // let mut tokns_buf: Vec = vec![]; - // tokns_buf.push(Token::new(0,TokenType::BOL,Location::new(0,0),String::from("BOL"))); + Ok(()) +} // if let Some(source) = get_source_buffer("test_value.asm") { +// // buffered reading +// let mut ast_list: Vec> = vec![]; +// for (line_no, read_buf) in source { +// if let Ok(read_buf) = read_buf { +// let mut l = Lexer::new(read_buf, line_no); +// let mut tokns_buf: Vec = vec![]; +// tokns_buf.push(Token::new(0,TokenType::BOL,Location::new(0,0),String::from("BOL"))); - // for tok in l { - // tokns_buf.push(tok); - // } - // // println!("{:?}", tokns_buf); +// for tok in l { +// tokns_buf.push(tok); +// } +// // println!("{:?}", tokns_buf); - // let mut p = Parser::new(tokns_buf.into_iter()); - // ast_list.push(p.parse_expression()); - // } else { - // println!("Error reading!"); - // } - // println!("{:?}",ast_list); - // } - // } -} +// let mut p = Parser::new(tokns_buf.into_iter()); +// ast_list.push(p.parse_expression()); +// } else { +// println!("Error reading!"); +// } +// println!("{:?}",ast_list); +// } +// } fn cast(req: Request) -> Result<(RequestId, R::Params), ExtractError> where diff --git a/test-value.asm b/test-value.asm index 8b13789..e69de29 100644 --- a/test-value.asm +++ b/test-value.asm @@ -1 +0,0 @@ - From 8f4a8105eecedaccc07536b50f446ce95a64989e Mon Sep 17 00:00:00 2001 From: shri-acha Date: Mon, 8 Dec 2025 21:20:24 +0545 Subject: [PATCH 39/50] add: instructions for jmp variants and some other instructions --- src/server/handlers.rs | 121 +++++++++++++++++++++++++++++++++++++++++ test-value.asm | 1 + 2 files changed, 122 insertions(+) diff --git a/src/server/handlers.rs b/src/server/handlers.rs index 41d798f..e5e4972 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -89,6 +89,127 @@ pub fn completion_handler(id: &RequestId, params: CompletionParams) -> serde_jso kind: Some(CompletionItemKind::KEYWORD), ..Default::default() }, + CompletionItem { + label: "STAX".to_string(), + detail: Some("STAX - Store accumulator indirect".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Stores the contents of the **accumulator** into the **memory location** pointed to by the **designated register pair**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "PUSH".to_string(), + detail: Some("PUSH - Push register pair to stack".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The contents of the specified **register pair** are **pushed onto the stack**, decrementing the **stack pointer** by 2.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "POP".to_string(), + detail: Some("POP - Pop register pair from stack".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Two bytes from the **stack** are **popped** and loaded into the specified **register pair**, incrementing the **stack pointer** by 2.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "INR".to_string(), + detail: Some("INR - Increment register".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Increments the contents of the specified **register** by **1**. Flags are affected except Carry.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "DCR".to_string(), + detail: Some("DCR - Decrement register".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Decrements the contents of the specified **register** by **1**. Flags are affected except Carry.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "DAD".to_string(), + detail: Some("DAD - Double add register pair".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Adds the contents of the specified **register pair** to the **HL pair**. Only the **Carry flag** is affected.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + // --- JMP Variants --- + CompletionItem { + label: "JMP".to_string(), + detail: Some("JMP - Unconditional jump".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Program execution **jumps** to the specified **16-bit address** unconditionally.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "JC".to_string(), + detail: Some("JC - Jump if carry".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Jumps to the given address **if the Carry flag = 1**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "JNC".to_string(), + detail: Some("JNC - Jump if no carry".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Jumps to the given address **if the Carry flag = 0**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "JZ".to_string(), + detail: Some("JZ - Jump if zero".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Jumps to the given address **if the Zero flag = 1**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "JNZ".to_string(), + detail: Some("JNZ - Jump if not zero".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Jumps to the given address **if the Zero flag = 0**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, ]; let result = CompletionResponse::Array(responses); diff --git a/test-value.asm b/test-value.asm index e69de29..6e53ddf 100644 --- a/test-value.asm +++ b/test-value.asm @@ -0,0 +1 @@ +JMP LABEL From f599e5adf5f3ed610038eb0930e26a6512558a91 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Tue, 9 Dec 2025 11:06:18 +0545 Subject: [PATCH 40/50] refactor: bindings for wasmabi --- Cargo.toml | 1 + README.md | 19 +++++++++++++++++++ src/main.rs | 42 +----------------------------------------- src/server/handlers.rs | 30 ++++++++++++++++++++++++------ src/server/mod.rs | 22 +++++++++++++++------- src/server/routers.rs | 17 +++++++++++++++-- test-value.asm | 1 - 7 files changed, 75 insertions(+), 57 deletions(-) create mode 100644 README.md diff --git a/Cargo.toml b/Cargo.toml index 627f628..591face 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,5 @@ lsp-server = "0.7.9" lsp-types = "0.97.0" serde = { version = "1", features = ["derive"] } serde_json = "1" +wasm-bindgen = "0.2.106" diff --git a/README.md b/README.md new file mode 100644 index 0000000..19ffa3f --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +``` +[ CodeMirror Editor ] + │ + ▼ + LSPClient (browser) + │ JSON-RPC + ▼ postMessage +┌──────────────────────────┐ +│ WebWorker (JS) │ +│ - Handles LSP messages │ +│ - Calls WASM functions │ +└───────────┬──────────────┘ + │ + ▼ + [ WASM Module ] + - completion() + - hover() + - parsing logic +``` diff --git a/src/main.rs b/src/main.rs index 3309c61..0dd00eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ use lsp_types::{ use server::{handlers, lsp85, routers}; use std::error::Error; -fn main() -> Result<(), Box> { +pub fn main() -> Result<(), Box> { let lsp = lsp85::build() .stdio() .enable_hover() @@ -55,43 +55,10 @@ fn main() -> Result<(), Box> { } eprintln!("got request: {:?}", req); - // let req = match cast::(req) { - // Ok((id, params)) => { - // eprintln!("got completion request #{}: {:?}", id, params); - // let sample_responses = vec![ - // CompletionItem::new_simple( - // "MOV".to_string(), - // "Move instruction".to_string(), - // ), - // CompletionItem::new_simple( - // "SUB".to_string(), - // "Subtract instruction".to_string(), - // ), - // CompletionItem::new_simple("ADD".to_string(), "Add values".to_string()), - // ]; - // let result = CompletionResponse::Array(sample_responses); - // let result = serde_json::to_value(&result).unwrap(); - // let resp = Response { - // id, - // result: Some(result), - // error: None, - // }; - // lsp.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; - // continue; - // } - // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), - // Err(ExtractError::MethodMismatch(req)) => req, - // }; lsp_router!(req,lsp,{ Completion=>handlers::completion_handler, HoverRequest=>handlers::hover_handler, }); - // let req = match cast::(req) { - // Ok((id, params)) => { - // } - // Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), - // Err(ExtractError::MethodMismatch(req)) => req, - // }; } Message::Response(rs) => { eprintln!("response: {:?}", rs); @@ -142,10 +109,3 @@ fn main() -> Result<(), Box> { // } // } -fn cast(req: Request) -> Result<(RequestId, R::Params), ExtractError> -where - R: lsp_types::request::Request, - R::Params: serde::de::DeserializeOwned, -{ - req.extract(R::METHOD) -} diff --git a/src/server/handlers.rs b/src/server/handlers.rs index e5e4972..a05fce9 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -6,7 +6,10 @@ use lsp_types::{ }; use serde_json; -pub fn completion_handler(id: &RequestId, params: CompletionParams) -> serde_json::Value { +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn completion_handler(id: &JsValue, params: JsValue) -> Result { eprintln!("got completion request #{}: {:?}", id, params); let responses = vec![ CompletionItem { @@ -213,10 +216,19 @@ pub fn completion_handler(id: &RequestId, params: CompletionParams) -> serde_jso ]; let result = CompletionResponse::Array(responses); - let result = serde_json::to_value(&result).unwrap(); - return result; + let result = serde_json::to_string(&result); + let result = match serde_json::to_string(&result){ + Ok(result)=>{ + return result; + } + Err(e)=>{ + return Err(e); + } + } } -pub fn hover_handler(id: &RequestId, params: HoverParams) -> serde_json::Value { + +#[wasm_bindgen] +pub fn hover_handler(id: &JsValue, params: JsValue) -> Result{ eprintln!("hovr request {}: {:?}", id, params); let hover_result = lsp_types::Hover { @@ -226,6 +238,12 @@ pub fn hover_handler(id: &RequestId, params: HoverParams) -> serde_json::Value { range: None, }; - let result = serde_json::to_value(&hover_result).unwrap(); - return result; + let result = match serde_json::to_string(&hover_result){ + Ok(result)=>{ + return result; + } + Err(e)=>{ + return Err(e); + } + } } diff --git a/src/server/mod.rs b/src/server/mod.rs index 6cc74d4..91309f7 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -39,19 +39,25 @@ impl lsp85 { self } + // expects self.connection defined before hand fn populate_client_cap(&mut self) { - let (id, params) = self + match self .conn .as_ref() .expect("[ERROR] Connection not initialized!") - .initialize_start() - .expect("[ERROR] Failed to initialize server!"); + .initialize_start(){ + Ok((id,params))=>{ + self.id = Some(id); - self.id = Some(id); + let init_params: InitializeParams = serde_json::from_value(params) + .expect("[[ERROR] Failed to parse initialization params!"); + self.client_cap = Some(init_params.capabilities); - let init_params: InitializeParams = serde_json::from_value(params) - .expect("[[ERROR] Failed to parse initialization params!"); - self.client_cap = Some(init_params.capabilities); + }, + Err(e)=>{ + eprintln!("[ERROR] Failed to initialize LSP"); + } + } } pub fn enable_completion(mut self) -> Self { self.server_cap @@ -69,7 +75,9 @@ impl lsp85 { self } + // expects self.connection and self.id pub fn initialize(self) -> Result> { + let initialize_data = serde_json::json!({ "capabilities": self.server_cap, "serverInfo": { diff --git a/src/server/routers.rs b/src/server/routers.rs index 8639940..6d5cf6f 100644 --- a/src/server/routers.rs +++ b/src/server/routers.rs @@ -1,3 +1,14 @@ +use lsp_server::{Request, RequestId, ExtractError}; +use serde::de::DeserializeOwned; + +pub fn cast(req: Request) -> Result<(RequestId, R::Params), ExtractError> +where + R: lsp_types::request::Request, + R::Params: serde::de::DeserializeOwned, +{ + req.extract(R::METHOD) +} + #[macro_export] macro_rules! lsp_router { ( @@ -5,15 +16,17 @@ macro_rules! lsp_router { $( $method:ty => $handler:path ),* $(,)? } ) => {{ + + use crate::server::routers::cast; $( let $req = match cast::<$method>($req) { Ok((id, params)) => { let resp = Response { - result: Some($handler(&id,params)), + result: Some(serde_json::Value($handler(&id,params))), id, error: None, }; - $state.conn.as_ref().unwrap().sender.send(Message::Response(resp))?; + $state.conn.as_ref().expect("[ERROR] Expected valid connection!").sender.send(Message::Response(resp))?; continue; }, Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), diff --git a/test-value.asm b/test-value.asm index 6e53ddf..e69de29 100644 --- a/test-value.asm +++ b/test-value.asm @@ -1 +0,0 @@ -JMP LABEL From 3e3abe8ab74f119cd21b12d056fd4b1f8d9398f4 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Wed, 10 Dec 2025 15:09:42 +0545 Subject: [PATCH 41/50] feat: add wasm bindings for functions and macros --- Cargo.toml | 1 + src/main.rs | 4 +- src/server/bindings.rs | 250 +++++++++++++++++++++++++++++++++++++++++ src/server/handlers.rs | 23 ++-- src/server/mod.rs | 1 + src/server/routers.rs | 34 +++++- 6 files changed, 296 insertions(+), 17 deletions(-) create mode 100644 src/server/bindings.rs diff --git a/Cargo.toml b/Cargo.toml index 591face..60d7fcd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" lsp-server = "0.7.9" lsp-types = "0.97.0" serde = { version = "1", features = ["derive"] } +serde-wasm-bindgen = "0.6.5" serde_json = "1" wasm-bindgen = "0.2.106" diff --git a/src/main.rs b/src/main.rs index 0dd00eb..ad48a29 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ use lsp_types::{ request::{Completion, HoverRequest}, }; use server::{handlers, lsp85, routers}; +use server::bindings::{wasm_completion_handler,wasm_hover_handler}; use std::error::Error; pub fn main() -> Result<(), Box> { @@ -86,7 +87,8 @@ pub fn main() -> Result<(), Box> { } Ok(()) -} // if let Some(source) = get_source_buffer("test_value.asm") { +} +// if let Some(source) = get_source_buffer("test_value.asm") { // // buffered reading // let mut ast_list: Vec> = vec![]; // for (line_no, read_buf) in source { diff --git a/src/server/bindings.rs b/src/server/bindings.rs new file mode 100644 index 0000000..6dd8cd4 --- /dev/null +++ b/src/server/bindings.rs @@ -0,0 +1,250 @@ +use wasm_bindgen::prelude::*; +use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; +use lsp_types::CompletionItemKind; +use lsp_types::{ + CompletionItem, CompletionParams, CompletionResponse, Documentation, HoverParams, + MarkupContent, MarkupKind, +}; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn wasm_completion_handler(id: JsValue, params: JsValue) -> Result { + // eprintln!("got completion request #{}: {:?}", id, params); + let responses = vec![ + CompletionItem { + label: "MOV".to_string(), + detail: Some("MOV - Move data between registers".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "`MOV` instruction **copies** the content of the **source register** into **destination register**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "MVI".to_string(), + detail: Some("MVI - Move immediate data".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The **8-bit data** is stored in the **destination register** of **memory**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "LDA".to_string(), + detail: Some("LDA - Load accumulator direct".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The contents of a **memory location**, specified by a **16-bit address** in the operand, are copied to the **accumulator**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "LDAX".to_string(), + detail: Some("LDAX - Load accumulator indirect".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The contents of the **designated register pair** point to a **memory location**. This instruction **copies** the contents of that memory location into the **accumulator**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "LXI".to_string(), + detail: Some("LXI - Load register pair immediate".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The instruction **loads 16-bit data** in the **register pair** designated in the operand.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "LHLD".to_string(), + detail: Some("LHLD - Load H and L registers direct".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The instruction **copies** the contents of the **memory location** pointed out by the **16-bit address** into **register L** and copies the contents of the **next memory location** into **register H**. The contents of the **source memory** are not altered.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "SUB".to_string(), + detail: Some("SUB - Subtract".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "**Subtract** instruction".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "ADD".to_string(), + detail: Some("ADD - Add".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "**Add** values".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + CompletionItem { + label: "STAX".to_string(), + detail: Some("STAX - Store accumulator indirect".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Stores the contents of the **accumulator** into the **memory location** pointed to by the **designated register pair**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "PUSH".to_string(), + detail: Some("PUSH - Push register pair to stack".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "The contents of the specified **register pair** are **pushed onto the stack**, decrementing the **stack pointer** by 2.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "POP".to_string(), + detail: Some("POP - Pop register pair from stack".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Two bytes from the **stack** are **popped** and loaded into the specified **register pair**, incrementing the **stack pointer** by 2.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "INR".to_string(), + detail: Some("INR - Increment register".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Increments the contents of the specified **register** by **1**. Flags are affected except Carry.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "DCR".to_string(), + detail: Some("DCR - Decrement register".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Decrements the contents of the specified **register** by **1**. Flags are affected except Carry.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "DAD".to_string(), + detail: Some("DAD - Double add register pair".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Adds the contents of the specified **register pair** to the **HL pair**. Only the **Carry flag** is affected.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + // --- JMP Variants --- + CompletionItem { + label: "JMP".to_string(), + detail: Some("JMP - Unconditional jump".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Program execution **jumps** to the specified **16-bit address** unconditionally.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "JC".to_string(), + detail: Some("JC - Jump if carry".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Jumps to the given address **if the Carry flag = 1**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "JNC".to_string(), + detail: Some("JNC - Jump if no carry".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Jumps to the given address **if the Carry flag = 0**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "JZ".to_string(), + detail: Some("JZ - Jump if zero".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Jumps to the given address **if the Zero flag = 1**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + + CompletionItem { + label: "JNZ".to_string(), + detail: Some("JNZ - Jump if not zero".to_string()), + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: "Jumps to the given address **if the Zero flag = 0**.".to_string(), + })), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }, + ]; + + let result = CompletionResponse::Array(responses); + let result = match serde_json::to_string(&result){ + Ok(result)=>{ + result + } + Err(e)=>{ + "[ERROR] failed to convert JSON-2-String".to_string().into() + } + }; + return Ok(serde_wasm_bindgen::to_value(&result)?); +} + +#[wasm_bindgen] +pub fn wasm_hover_handler(id: JsValue, params:JsValue ) -> Result{ + // eprintln!("hovr request {}: {:?}", id, params); + + let hover_result = lsp_types::Hover { + contents: lsp_types::HoverContents::Scalar(lsp_types::MarkedString::String( + "dummy hover info".to_string(), + )), + range: None, + }; + + let result = match serde_json::to_string(&hover_result){ + Ok(result)=>{ + result + } + Err(_)=>{ + return Err("[ERROR] failed to convert JSON-2-String".to_string().into()) + } + }; + return Ok(serde_wasm_bindgen::to_value(&result)?); +} diff --git a/src/server/handlers.rs b/src/server/handlers.rs index a05fce9..990fb8d 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -4,12 +4,9 @@ use lsp_types::{ CompletionItem, CompletionParams, CompletionResponse, Documentation, HoverParams, MarkupContent, MarkupKind, }; -use serde_json; -use wasm_bindgen::prelude::*; -#[wasm_bindgen] -pub fn completion_handler(id: &JsValue, params: JsValue) -> Result { +pub fn completion_handler(id: &RequestId, params: CompletionParams ) -> Result { eprintln!("got completion request #{}: {:?}", id, params); let responses = vec![ CompletionItem { @@ -216,19 +213,18 @@ pub fn completion_handler(id: &JsValue, params: JsValue) -> Result{ - return result; + serde_json::to_value(&result) } Err(e)=>{ - return Err(e); + Err(e) } - } + }; + return Ok(result?); } -#[wasm_bindgen] -pub fn hover_handler(id: &JsValue, params: JsValue) -> Result{ +pub fn hover_handler(id: &RequestId, params: HoverParams ) -> Result{ eprintln!("hovr request {}: {:?}", id, params); let hover_result = lsp_types::Hover { @@ -240,10 +236,11 @@ pub fn hover_handler(id: &JsValue, params: JsValue) -> Result{ let result = match serde_json::to_string(&hover_result){ Ok(result)=>{ - return result; + serde_json::to_value(&result) } Err(e)=>{ - return Err(e); + Err(e) } - } + }; + return Ok(result?); } diff --git a/src/server/mod.rs b/src/server/mod.rs index 91309f7..4bebe0b 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,5 +1,6 @@ pub mod handlers; pub mod routers; +pub mod bindings; use lsp_server::{Connection, IoThreads, Message, Notification, Request, RequestId}; use lsp_types::{ diff --git a/src/server/routers.rs b/src/server/routers.rs index 6d5cf6f..aed224c 100644 --- a/src/server/routers.rs +++ b/src/server/routers.rs @@ -9,6 +9,33 @@ where req.extract(R::METHOD) } +#[macro_export] +macro_rules! wasm_lsp_router { + ( + $req:ident, $state:ident, { + $( $method:ty => $handler:path ),* $(,)? + } + ) => {{ + use crate::server::routers::cast; + +$( + let $req = match cast::<$method>($req) { + Ok((id, params)) => { + let resp = Response { + result: Some(serde_wasm_bindgen::from_value($handler(serde_wasm_bindgen::to_value(&serde_json::to_string(&id)?)?,serde_wasm_bindgen::to_value(&serde_json::to_string(¶ms)?)?).expect("[ERROR] Failure in communication!"))?) , + id, + error: None, + }; + $state.conn.as_ref().expect("[ERROR] Expected valid connection!").sender.send(Message::Response(resp)); + continue; + }, + Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), + Err(ExtractError::MethodMismatch(req)) => req, + }; +)* + }}; +} + #[macro_export] macro_rules! lsp_router { ( @@ -16,17 +43,18 @@ macro_rules! lsp_router { $( $method:ty => $handler:path ),* $(,)? } ) => {{ + use crate::server::routers::cast; - use crate::server::routers::cast; $( let $req = match cast::<$method>($req) { Ok((id, params)) => { let resp = Response { - result: Some(serde_json::Value($handler(&id,params))), + result: Some($handler(&id,params).expect("[ERROR] Expected non-empty response")), id, error: None, }; - $state.conn.as_ref().expect("[ERROR] Expected valid connection!").sender.send(Message::Response(resp))?; + eprintln!("{:?}",resp); + $state.conn.as_ref().expect("[ERROR] Expected valid connection!").sender.send(Message::Response(resp)); continue; }, Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), From 0dcd68374270abdd9ee10017d5146d22a16bc6a7 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Wed, 10 Dec 2025 15:21:56 +0545 Subject: [PATCH 42/50] chore: fixed up build for non-wasm build --- src/server/handlers.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/server/handlers.rs b/src/server/handlers.rs index 990fb8d..33420a6 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -213,15 +213,14 @@ pub fn completion_handler(id: &RequestId, params: CompletionParams ) -> Result{ - serde_json::to_value(&result) + return Ok(result) } Err(e)=>{ - Err(e) + return Err(e) } }; - return Ok(result?); } pub fn hover_handler(id: &RequestId, params: HoverParams ) -> Result{ @@ -234,13 +233,12 @@ pub fn hover_handler(id: &RequestId, params: HoverParams ) -> Result{ - serde_json::to_value(&result) + return Ok(result); } Err(e)=>{ - Err(e) + return Err(e); } }; - return Ok(result?); } From 1e14c742b426577716a5af35dadfed974803e091 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Wed, 10 Dec 2025 15:36:24 +0545 Subject: [PATCH 43/50] refactor/add: generated wasm bindings for methods --- Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 60d7fcd..67cd0c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,7 @@ +[lib] +crate-type = ["cdylib", "rlib"] +path = "src/server/bindings.rs" + [package] name = "lsp85" version = "0.1.0" @@ -10,4 +14,3 @@ serde = { version = "1", features = ["derive"] } serde-wasm-bindgen = "0.6.5" serde_json = "1" wasm-bindgen = "0.2.106" - From 8bc745b7478bff8e9f189340b8b9e2dd3f006478 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Wed, 10 Dec 2025 16:34:27 +0545 Subject: [PATCH 44/50] feat: add common interface for bindings --- src/server/bindings.rs | 34 ++++++++++++++++++++++++++++++++++ src/server/routers.rs | 5 ++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/server/bindings.rs b/src/server/bindings.rs index 6dd8cd4..638d180 100644 --- a/src/server/bindings.rs +++ b/src/server/bindings.rs @@ -8,6 +8,40 @@ use lsp_types::{ use wasm_bindgen::prelude::*; +#[wasm_bindgen] +pub fn wasm_request_handler (req: JsValue)->Result{ + + let msg = serde_wasm_bindgen::from_value(req) + .map_error(|e| JsValue::from_str(&format!("Invalid request: {:?}",e)))?; + match msg { + Message::Request(req) => { + eprintln!("got request: {:?}", req); + wasm_lsp_router!(req,{ + Completion=>handlers::completion_handler, + HoverRequest=>handlers::hover_handler, + }); + } + Message::Response(rs) => { + eprintln!("response: {:?}", rs); + } + Message::Notification(n) => { + match &n { + Notification { method, .. } + if *method == String::from("textDocument/didSave") => + { + eprintln!("File saved!"); + } + e => { + eprintln!("unimplemented {:?}", e); + } + } + eprintln!("notification: {:?}", n); + } + } + +} + + #[wasm_bindgen] pub fn wasm_completion_handler(id: JsValue, params: JsValue) -> Result { // eprintln!("got completion request #{}: {:?}", id, params); diff --git a/src/server/routers.rs b/src/server/routers.rs index aed224c..b2d5c6f 100644 --- a/src/server/routers.rs +++ b/src/server/routers.rs @@ -12,7 +12,7 @@ where #[macro_export] macro_rules! wasm_lsp_router { ( - $req:ident, $state:ident, { + $req:ident, { $( $method:ty => $handler:path ),* $(,)? } ) => {{ @@ -26,8 +26,7 @@ $( id, error: None, }; - $state.conn.as_ref().expect("[ERROR] Expected valid connection!").sender.send(Message::Response(resp)); - continue; + return resp; }, Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), Err(ExtractError::MethodMismatch(req)) => req, From 9ac3f55f98b7051480f99b8767b83be9af07a3d1 Mon Sep 17 00:00:00 2001 From: irhs0 Date: Wed, 10 Dec 2025 21:07:44 +0545 Subject: [PATCH 45/50] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 19ffa3f..795bed4 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,6 @@ - hover() - parsing logic ``` +(x) - Code completions +image +() Populate for all the instructions From 816717148ce1bf57d18a51fec84d6c2300a5ba81 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 12 Dec 2025 08:49:36 +0545 Subject: [PATCH 46/50] refactor: worked on adding library to create bindings --- src/lib.rs | 2 ++ src/server/bindings.rs | 18 +++++++++++------- src/server/mod.rs | 3 ++- src/server/routers.rs | 1 + 4 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 src/lib.rs diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..dc77a29 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +#[macro_use] +pub mod server; diff --git a/src/server/bindings.rs b/src/server/bindings.rs index 638d180..960f99e 100644 --- a/src/server/bindings.rs +++ b/src/server/bindings.rs @@ -5,37 +5,41 @@ use lsp_types::{ CompletionItem, CompletionParams, CompletionResponse, Documentation, HoverParams, MarkupContent, MarkupKind, }; - +use crate::server::handlers; +use lsp_types::request::{Completion, HoverRequest}; use wasm_bindgen::prelude::*; + #[wasm_bindgen] pub fn wasm_request_handler (req: JsValue)->Result{ let msg = serde_wasm_bindgen::from_value(req) - .map_error(|e| JsValue::from_str(&format!("Invalid request: {:?}",e)))?; + .map_err(|e| JsValue::from_str(&format!("Invalid request: {:?}",e)))?; match msg { Message::Request(req) => { - eprintln!("got request: {:?}", req); + // eprintln!("got request: {:?}", req); wasm_lsp_router!(req,{ Completion=>handlers::completion_handler, HoverRequest=>handlers::hover_handler, }); + return Ok(format!("Request: {:?}",req).into()); } Message::Response(rs) => { - eprintln!("response: {:?}", rs); + // eprintln!("response: {:?}", rs); + return Ok(format!("Response: {:?}",rs).into()); } Message::Notification(n) => { match &n { Notification { method, .. } if *method == String::from("textDocument/didSave") => { - eprintln!("File saved!"); + return Ok(format!("File saved!").into()); } e => { - eprintln!("unimplemented {:?}", e); + return Err(format!("Error in saving file!").into()); } } - eprintln!("notification: {:?}", n); + return Ok(format!("notification: {:?}",n).into()); } } diff --git a/src/server/mod.rs b/src/server/mod.rs index 4bebe0b..1ae0e6e 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,5 +1,6 @@ -pub mod handlers; +#[macro_use] pub mod routers; +pub mod handlers; pub mod bindings; use lsp_server::{Connection, IoThreads, Message, Notification, Request, RequestId}; diff --git a/src/server/routers.rs b/src/server/routers.rs index b2d5c6f..3689915 100644 --- a/src/server/routers.rs +++ b/src/server/routers.rs @@ -35,6 +35,7 @@ $( }}; } + #[macro_export] macro_rules! lsp_router { ( From f00859312b2fe4b2f3a67a8e4c9f6f0d49060975 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Wed, 17 Dec 2025 15:07:05 +0545 Subject: [PATCH 47/50] fix: removed introduced new bindings handler wrapper --- Cargo.toml | 2 +- src/main.rs | 3 +-- src/server/bindings.rs | 54 +++++++++++++++--------------------------- src/server/handlers.rs | 29 ++++++++++++----------- src/server/mod.rs | 27 ++++++++++----------- src/server/routers.rs | 8 +++---- 6 files changed, 53 insertions(+), 70 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 67cd0c5..399e300 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [lib] crate-type = ["cdylib", "rlib"] -path = "src/server/bindings.rs" +path = "src/lib.rs" [package] name = "lsp85" diff --git a/src/main.rs b/src/main.rs index ad48a29..dd2d0a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,8 +11,8 @@ use lsp_types::{ CompletionItem, CompletionResponse, request::{Completion, HoverRequest}, }; +use server::bindings::{wasm_completion_handler, wasm_hover_handler}; use server::{handlers, lsp85, routers}; -use server::bindings::{wasm_completion_handler,wasm_hover_handler}; use std::error::Error; pub fn main() -> Result<(), Box> { @@ -110,4 +110,3 @@ pub fn main() -> Result<(), Box> { // println!("{:?}",ast_list); // } // } - diff --git a/src/server/bindings.rs b/src/server/bindings.rs index 960f99e..5e472bc 100644 --- a/src/server/bindings.rs +++ b/src/server/bindings.rs @@ -1,53 +1,46 @@ -use wasm_bindgen::prelude::*; +use crate::server::handlers; use lsp_server::{ExtractError, Message, Notification, Request, RequestId, Response}; use lsp_types::CompletionItemKind; +use lsp_types::request::{Completion, HoverRequest}; use lsp_types::{ CompletionItem, CompletionParams, CompletionResponse, Documentation, HoverParams, MarkupContent, MarkupKind, }; -use crate::server::handlers; -use lsp_types::request::{Completion, HoverRequest}; use wasm_bindgen::prelude::*; - +use wasm_bindgen::prelude::*; #[wasm_bindgen] -pub fn wasm_request_handler (req: JsValue)->Result{ - +pub fn wasm_request_handler(req: JsValue) -> Result { let msg = serde_wasm_bindgen::from_value(req) - .map_err(|e| JsValue::from_str(&format!("Invalid request: {:?}",e)))?; + .map_err(|e| JsValue::from_str(&format!("Invalid request: {:?}", e)))?; match msg { Message::Request(req) => { // eprintln!("got request: {:?}", req); wasm_lsp_router!(req,{ - Completion=>handlers::completion_handler, - HoverRequest=>handlers::hover_handler, + Completion=>wasm_completion_handler, + HoverRequest=>wasm_hover_handler, }); - return Ok(format!("Request: {:?}",req).into()); + return Ok(format!("Request handled and routed!").into()); } Message::Response(rs) => { // eprintln!("response: {:?}", rs); - return Ok(format!("Response: {:?}",rs).into()); + return Ok(format!("Response: {:?}", rs).into()); } Message::Notification(n) => { match &n { - Notification { method, .. } - if *method == String::from("textDocument/didSave") => - { + Notification { method, .. } if *method == String::from("textDocument/didSave") => { return Ok(format!("File saved!").into()); } e => { return Err(format!("Error in saving file!").into()); } } - return Ok(format!("notification: {:?}",n).into()); + return Ok(format!("notification: {:?}", n).into()); } } - } - -#[wasm_bindgen] -pub fn wasm_completion_handler(id: JsValue, params: JsValue) -> Result { +pub fn wasm_completion_handler(id: &RequestId, params: &CompletionParams) -> Result { // eprintln!("got completion request #{}: {:?}", id, params); let responses = vec![ CompletionItem { @@ -254,19 +247,14 @@ pub fn wasm_completion_handler(id: JsValue, params: JsValue) -> Result{ - result - } - Err(e)=>{ - "[ERROR] failed to convert JSON-2-String".to_string().into() - } + let result = match serde_json::to_string(&result) { + Ok(result) => result, + Err(e) => "[ERROR] failed to convert JSON-2-String".to_string().into(), }; return Ok(serde_wasm_bindgen::to_value(&result)?); } -#[wasm_bindgen] -pub fn wasm_hover_handler(id: JsValue, params:JsValue ) -> Result{ +pub fn wasm_hover_handler(id: &RequestId, params: &HoverParams) -> Result { // eprintln!("hovr request {}: {:?}", id, params); let hover_result = lsp_types::Hover { @@ -276,13 +264,9 @@ pub fn wasm_hover_handler(id: JsValue, params:JsValue ) -> Result{ - result - } - Err(_)=>{ - return Err("[ERROR] failed to convert JSON-2-String".to_string().into()) - } + let result = match serde_json::to_string(&hover_result) { + Ok(result) => result, + Err(_) => return Err("[ERROR] failed to convert JSON-2-String".to_string().into()), }; return Ok(serde_wasm_bindgen::to_value(&result)?); } diff --git a/src/server/handlers.rs b/src/server/handlers.rs index 33420a6..ef70827 100644 --- a/src/server/handlers.rs +++ b/src/server/handlers.rs @@ -5,8 +5,10 @@ use lsp_types::{ MarkupContent, MarkupKind, }; - -pub fn completion_handler(id: &RequestId, params: CompletionParams ) -> Result { +pub fn completion_handler( + id: &RequestId, + params: CompletionParams, +) -> Result { eprintln!("got completion request #{}: {:?}", id, params); let responses = vec![ CompletionItem { @@ -213,17 +215,16 @@ pub fn completion_handler(id: &RequestId, params: CompletionParams ) -> Result{ - return Ok(result) - } - Err(e)=>{ - return Err(e) - } + let result = match serde_json::to_value(&result) { + Ok(result) => return Ok(result), + Err(e) => return Err(e), }; } -pub fn hover_handler(id: &RequestId, params: HoverParams ) -> Result{ +pub fn hover_handler( + id: &RequestId, + params: HoverParams, +) -> Result { eprintln!("hovr request {}: {:?}", id, params); let hover_result = lsp_types::Hover { @@ -233,12 +234,12 @@ pub fn hover_handler(id: &RequestId, params: HoverParams ) -> Result{ + let result = match serde_json::to_value(&hover_result) { + Ok(result) => { return Ok(result); } - Err(e)=>{ - return Err(e); + Err(e) => { + return Err(e); } }; } diff --git a/src/server/mod.rs b/src/server/mod.rs index 1ae0e6e..87dd49d 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,7 +1,7 @@ #[macro_use] pub mod routers; -pub mod handlers; pub mod bindings; +pub mod handlers; use lsp_server::{Connection, IoThreads, Message, Notification, Request, RequestId}; use lsp_types::{ @@ -43,23 +43,23 @@ impl lsp85 { // expects self.connection defined before hand fn populate_client_cap(&mut self) { - match self + match self .conn .as_ref() .expect("[ERROR] Connection not initialized!") - .initialize_start(){ - Ok((id,params))=>{ - self.id = Some(id); - - let init_params: InitializeParams = serde_json::from_value(params) - .expect("[[ERROR] Failed to parse initialization params!"); - self.client_cap = Some(init_params.capabilities); + .initialize_start() + { + Ok((id, params)) => { + self.id = Some(id); - }, - Err(e)=>{ - eprintln!("[ERROR] Failed to initialize LSP"); - } + let init_params: InitializeParams = serde_json::from_value(params) + .expect("[[ERROR] Failed to parse initialization params!"); + self.client_cap = Some(init_params.capabilities); } + Err(e) => { + eprintln!("[ERROR] Failed to initialize LSP"); + } + } } pub fn enable_completion(mut self) -> Self { self.server_cap @@ -79,7 +79,6 @@ impl lsp85 { // expects self.connection and self.id pub fn initialize(self) -> Result> { - let initialize_data = serde_json::json!({ "capabilities": self.server_cap, "serverInfo": { diff --git a/src/server/routers.rs b/src/server/routers.rs index 3689915..f328813 100644 --- a/src/server/routers.rs +++ b/src/server/routers.rs @@ -1,4 +1,4 @@ -use lsp_server::{Request, RequestId, ExtractError}; +use lsp_server::{ExtractError, Request, RequestId}; use serde::de::DeserializeOwned; pub fn cast(req: Request) -> Result<(RequestId, R::Params), ExtractError> @@ -22,11 +22,12 @@ $( let $req = match cast::<$method>($req) { Ok((id, params)) => { let resp = Response { - result: Some(serde_wasm_bindgen::from_value($handler(serde_wasm_bindgen::to_value(&serde_json::to_string(&id)?)?,serde_wasm_bindgen::to_value(&serde_json::to_string(¶ms)?)?).expect("[ERROR] Failure in communication!"))?) , + result: Some( + serde_wasm_bindgen::from_value( $handler( &id ,¶ms).expect("[ERROR] Failure in communication!"))?) , id, error: None, }; - return resp; + return Ok(serde_wasm_bindgen::to_value(&resp)?); }, Err(err @ ExtractError::JsonError { .. }) => panic!("{:?}", err), Err(ExtractError::MethodMismatch(req)) => req, @@ -35,7 +36,6 @@ $( }}; } - #[macro_export] macro_rules! lsp_router { ( From e46686ac5b3557b18c0de83a0186308485b28144 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Wed, 17 Dec 2025 15:53:51 +0545 Subject: [PATCH 48/50] Remove lsp85 submodule --- .gitmodules | 3 --- src/lsp/lsp85 | 1 - 2 files changed, 4 deletions(-) delete mode 160000 src/lsp/lsp85 diff --git a/.gitmodules b/.gitmodules index 3e27885..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "src/lsp/lsp85"] - path = src/lsp/lsp85 - url = git@github.com:shri-acha/lsp85.git/ diff --git a/src/lsp/lsp85 b/src/lsp/lsp85 deleted file mode 160000 index bb184b9..0000000 --- a/src/lsp/lsp85 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bb184b92f82c3caa8ca5c555d01d455ae0d2379c From 43e1e7574efabda31f350a42d66d751936bc1886 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Wed, 17 Dec 2025 15:57:38 +0545 Subject: [PATCH 49/50] added: lsp85 as a subtree --- lsp85/test-value.asm | 0 {lsp85 => src/lsp/lsp85}/.gitignore | 0 {lsp85 => src/lsp/lsp85}/Cargo.toml | 0 {lsp85 => src/lsp/lsp85}/README.md | 0 {lsp85 => src/lsp/lsp85}/src/frontend/lexer.rs | 0 {lsp85 => src/lsp/lsp85}/src/frontend/mod.rs | 0 {lsp85 => src/lsp/lsp85}/src/frontend/parser.rs | 0 {lsp85 => src/lsp/lsp85}/src/frontend/token.rs | 0 {lsp85 => src/lsp/lsp85}/src/frontend/utils/files.rs | 0 {lsp85 => src/lsp/lsp85}/src/frontend/utils/mod.rs | 0 {lsp85 => src/lsp/lsp85}/src/lib.rs | 0 {lsp85 => src/lsp/lsp85}/src/main.rs | 0 {lsp85 => src/lsp/lsp85}/src/server/bindings.rs | 0 {lsp85 => src/lsp/lsp85}/src/server/handlers.rs | 0 {lsp85 => src/lsp/lsp85}/src/server/mod.rs | 0 {lsp85 => src/lsp/lsp85}/src/server/routers.rs | 0 16 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lsp85/test-value.asm rename {lsp85 => src/lsp/lsp85}/.gitignore (100%) rename {lsp85 => src/lsp/lsp85}/Cargo.toml (100%) rename {lsp85 => src/lsp/lsp85}/README.md (100%) rename {lsp85 => src/lsp/lsp85}/src/frontend/lexer.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/frontend/mod.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/frontend/parser.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/frontend/token.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/frontend/utils/files.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/frontend/utils/mod.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/lib.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/main.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/server/bindings.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/server/handlers.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/server/mod.rs (100%) rename {lsp85 => src/lsp/lsp85}/src/server/routers.rs (100%) diff --git a/lsp85/test-value.asm b/lsp85/test-value.asm deleted file mode 100644 index e69de29..0000000 diff --git a/lsp85/.gitignore b/src/lsp/lsp85/.gitignore similarity index 100% rename from lsp85/.gitignore rename to src/lsp/lsp85/.gitignore diff --git a/lsp85/Cargo.toml b/src/lsp/lsp85/Cargo.toml similarity index 100% rename from lsp85/Cargo.toml rename to src/lsp/lsp85/Cargo.toml diff --git a/lsp85/README.md b/src/lsp/lsp85/README.md similarity index 100% rename from lsp85/README.md rename to src/lsp/lsp85/README.md diff --git a/lsp85/src/frontend/lexer.rs b/src/lsp/lsp85/src/frontend/lexer.rs similarity index 100% rename from lsp85/src/frontend/lexer.rs rename to src/lsp/lsp85/src/frontend/lexer.rs diff --git a/lsp85/src/frontend/mod.rs b/src/lsp/lsp85/src/frontend/mod.rs similarity index 100% rename from lsp85/src/frontend/mod.rs rename to src/lsp/lsp85/src/frontend/mod.rs diff --git a/lsp85/src/frontend/parser.rs b/src/lsp/lsp85/src/frontend/parser.rs similarity index 100% rename from lsp85/src/frontend/parser.rs rename to src/lsp/lsp85/src/frontend/parser.rs diff --git a/lsp85/src/frontend/token.rs b/src/lsp/lsp85/src/frontend/token.rs similarity index 100% rename from lsp85/src/frontend/token.rs rename to src/lsp/lsp85/src/frontend/token.rs diff --git a/lsp85/src/frontend/utils/files.rs b/src/lsp/lsp85/src/frontend/utils/files.rs similarity index 100% rename from lsp85/src/frontend/utils/files.rs rename to src/lsp/lsp85/src/frontend/utils/files.rs diff --git a/lsp85/src/frontend/utils/mod.rs b/src/lsp/lsp85/src/frontend/utils/mod.rs similarity index 100% rename from lsp85/src/frontend/utils/mod.rs rename to src/lsp/lsp85/src/frontend/utils/mod.rs diff --git a/lsp85/src/lib.rs b/src/lsp/lsp85/src/lib.rs similarity index 100% rename from lsp85/src/lib.rs rename to src/lsp/lsp85/src/lib.rs diff --git a/lsp85/src/main.rs b/src/lsp/lsp85/src/main.rs similarity index 100% rename from lsp85/src/main.rs rename to src/lsp/lsp85/src/main.rs diff --git a/lsp85/src/server/bindings.rs b/src/lsp/lsp85/src/server/bindings.rs similarity index 100% rename from lsp85/src/server/bindings.rs rename to src/lsp/lsp85/src/server/bindings.rs diff --git a/lsp85/src/server/handlers.rs b/src/lsp/lsp85/src/server/handlers.rs similarity index 100% rename from lsp85/src/server/handlers.rs rename to src/lsp/lsp85/src/server/handlers.rs diff --git a/lsp85/src/server/mod.rs b/src/lsp/lsp85/src/server/mod.rs similarity index 100% rename from lsp85/src/server/mod.rs rename to src/lsp/lsp85/src/server/mod.rs diff --git a/lsp85/src/server/routers.rs b/src/lsp/lsp85/src/server/routers.rs similarity index 100% rename from lsp85/src/server/routers.rs rename to src/lsp/lsp85/src/server/routers.rs From 32aa788ea61d69b30fd761d2afa3de9a6e8fa9a9 Mon Sep 17 00:00:00 2001 From: shri-acha Date: Fri, 19 Dec 2025 21:17:06 +0545 Subject: [PATCH 50/50] init: lsp interface --- src/lsp/interface.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/lsp/interface.ts diff --git a/src/lsp/interface.ts b/src/lsp/interface.ts new file mode 100644 index 0000000..6efe22d --- /dev/null +++ b/src/lsp/interface.ts @@ -0,0 +1,12 @@ +import {Transport,LSPClient } from "@codemirror/lsp-client" + + + +function WasmWebTransport(path: string): Promise { + let handlers: ((value: string) => void)[] = [] + let worker = new Worker(path); + worker.onmessage = e => { for (let h of handlers) h(e.data.toString()) } + return new Promise(resolve => { + worker.onopen = () => resolve() + }) +}