11#![ feature( iter_intersperse) ]
22
3- use std:: path:: Path ;
3+ use std:: { collections :: HashMap , path:: Path } ;
44
55use lexer:: Lexer ;
66use parser:: {
@@ -10,8 +10,8 @@ use parser::{
1010 DictLiteral , EchoCommand , ElseCommand , ElseIfCommand , ExCommand ,
1111 ExecuteCommand , Expandable , ExportCommand , Expression , ForCommand ,
1212 GroupedExpression , Heredoc , Identifier , IfCommand , ImportCommand ,
13- IndexExpression , IndexType , InfixExpression , InnerType , Lambda , Literal ,
14- MethodCall , MutationStatement , PrefixExpression , RawIdentifier , Register ,
13+ IndexExpression , IndexType , InfixExpression , Lambda , Literal , MethodCall ,
14+ MutationStatement , Operator , PrefixExpression , RawIdentifier , Register ,
1515 ReturnCommand , ScopedIdentifier , SharedCommand , Signature ,
1616 StatementCommand , Ternary , TryCommand , Type , UnpackIdentifier , UserCommand ,
1717 VarCommand , Vim9ScriptCommand , VimBoolean , VimKey , VimNumber , VimOption ,
@@ -68,6 +68,24 @@ impl State {
6868 let res = f ( self ) ;
6969 ( res, self . scopes . pop ( ) . expect ( "balanced scopes" ) )
7070 }
71+
72+ fn push_declaration ( & mut self , expr_1 : & Expression , expr_2 : Type ) -> Type {
73+ self . scopes
74+ . last_mut ( )
75+ . unwrap ( )
76+ . push_declaration ( expr_1, expr_2)
77+ }
78+
79+ fn lookup_declaration ( & self , expr_1 : & Expression ) -> Option < Type > {
80+ match Scope :: declaration_key ( expr_1) {
81+ Some ( key) => self
82+ . scopes
83+ . iter ( )
84+ . rev ( )
85+ . find_map ( |s| s. declarations . get ( & key) . cloned ( ) ) ,
86+ None => None ,
87+ }
88+ }
7189}
7290
7391macro_rules! find_scope {
@@ -94,24 +112,33 @@ macro_rules! scope_or_empty {
94112 } } ;
95113}
96114
97- #[ derive( PartialEq , Eq , Debug ) ]
115+ #[ derive( PartialEq , Eq , Debug , Default ) ]
98116pub enum ScopeKind {
117+ #[ default]
99118 TopLevel ,
100119 Function ,
101- While { has_continue : bool } ,
102- For { has_continue : bool } ,
120+ While {
121+ has_continue : bool ,
122+ } ,
123+ For {
124+ has_continue : bool ,
125+ } ,
103126 If ,
104127}
105128
106- #[ derive( Debug ) ]
129+ #[ derive( Debug , Default ) ]
107130pub struct Scope {
108131 kind : ScopeKind ,
109132 deferred : usize ,
133+ declarations : HashMap < String , Type > ,
110134}
111135
112136impl Scope {
113137 pub fn new ( kind : ScopeKind ) -> Self {
114- Self { kind, deferred : 0 }
138+ Self {
139+ kind,
140+ ..Default :: default ( )
141+ }
115142 }
116143
117144 /// Whether the current scope contains any unique behavior for embedded continues
@@ -122,6 +149,28 @@ impl Scope {
122149 _ => false ,
123150 }
124151 }
152+
153+ pub fn declaration_key ( expr : & Expression ) -> Option < String > {
154+ match expr {
155+ Expression :: Identifier ( ident) => match & ident {
156+ Identifier :: Raw ( raw) => Some ( raw. name . clone ( ) ) ,
157+ Identifier :: Scope ( _) => return None ,
158+ Identifier :: Unpacked ( _) => return None ,
159+ Identifier :: Ellipsis => return None ,
160+ } ,
161+ _ => return None ,
162+ }
163+ }
164+
165+ pub fn push_declaration ( & mut self , expr : & Expression , ty : Type ) -> Type {
166+ let key = match Self :: declaration_key ( expr) {
167+ Some ( key) => key,
168+ None => return ty,
169+ } ;
170+
171+ self . declarations . insert ( key, ty. clone ( ) ) ;
172+ ty
173+ }
125174}
126175
127176pub trait Generate {
@@ -423,19 +472,19 @@ impl Generate for DeclCommand {
423472 "local {} = {}" ,
424473 self . name. gen ( state) ,
425474 match & self . ty {
426- Some ( ty) => match ty. inner {
427- InnerType :: Any => "0" ,
428- InnerType :: Bool => "false" ,
429- InnerType :: Number => "0" ,
430- InnerType :: Float => "0" ,
431- InnerType :: String => "''" ,
432- InnerType :: List { .. } => "{}" ,
433- InnerType :: Dict { .. } => "vim.empty_dict()" ,
434- InnerType :: Job => todo!( ) ,
435- InnerType :: Channel => todo!( ) ,
436- InnerType :: Void => "nil" ,
437- InnerType :: Func ( _) => "function() end" ,
438- InnerType :: Blob => unreachable!( ) ,
475+ Some ( ty) => match ty {
476+ Type :: Any => "0" ,
477+ Type :: Bool => "false" ,
478+ Type :: Number => "0" ,
479+ Type :: Float => "0" ,
480+ Type :: String => "''" ,
481+ Type :: List { .. } => "{}" ,
482+ Type :: Dict { .. } => "vim.empty_dict()" ,
483+ Type :: Job => todo!( ) ,
484+ Type :: Channel => todo!( ) ,
485+ Type :: Void => "nil" ,
486+ Type :: Func ( _) => "function() end" ,
487+ Type :: Blob => unreachable!( ) ,
439488 } ,
440489 None => "nil" ,
441490 }
@@ -715,14 +764,30 @@ impl Generate for IfCommand {
715764 None => "" . to_string ( ) ,
716765 } ;
717766
767+ let condition = self . condition . gen ( state) ;
768+
769+ // TODO: Numbers are automatically coerced into bools for vim
770+ // so sometimes the type system lies to us.
771+ //
772+ // Perhaps I need an additional type: BoolNumber that we use
773+ // for most cases of vim, and we only escalate to Bool when we're confident
774+ // that this what is happening.
775+ //
776+ // This would allow us to remove the NVIM9.bool condition (assuming the type
777+ // system is correct in vim9script)
778+ //
779+ // let condition = match guess_type_of_expr(state, &self.condition).inner {
780+ // Type::Bool => condition,
781+ // _ => format!("NVIM9.bool({condition})"),
782+ // };
783+
718784 format ! (
719785 r#"
720- if NVIM9.bool({}) then
786+ if NVIM9.bool({condition }) then
721787 {}
722788{}
723789{}
724790end"# ,
725- self . condition. gen ( state) ,
726791 self . body. gen ( state) ,
727792 self . elseifs
728793 . iter( )
@@ -740,7 +805,7 @@ impl Generate for ElseIfCommand {
740805 fn gen ( & self , state : & mut State ) -> String {
741806 format ! (
742807 r#"
743- elseif {} then
808+ elseif NVIM9.bool({}) then
744809 {}
745810 "# ,
746811 self . condition. gen ( state) ,
@@ -802,17 +867,68 @@ fn identifier_list(state: &mut State, unpacked: &UnpackIdentifier) -> String {
802867 . collect ( )
803868}
804869
870+ fn guess_type_of_expr ( _: & State , expr : & Expression ) -> Type {
871+ match expr {
872+ Expression :: Number ( _) => Type :: Number ,
873+ Expression :: String ( _) => Type :: String ,
874+ Expression :: Boolean ( _) => Type :: Bool ,
875+ Expression :: Call ( c) => match c. name ( ) {
876+ Some ( ident) => match ident {
877+ // TODO: Use our very cool new generated stuff here
878+ Identifier :: Raw ( raw) => match raw. name . as_str ( ) {
879+ "charcol" => Type :: Number ,
880+ _ => Type :: Any ,
881+ } ,
882+ _ => Type :: Any ,
883+ } ,
884+ _ => Type :: Any ,
885+ } ,
886+ Expression :: Infix ( infix) => {
887+ if infix. operator . is_comparison ( ) {
888+ return Type :: Bool ;
889+ } else if matches ! ( infix. operator, Operator :: And | Operator :: Or ) {
890+ // if guess_type_of_expr(infix.left) {}
891+ Type :: Any
892+ // todo!()
893+ } else {
894+ Type :: Any
895+ }
896+ }
897+ _ => Type :: Any ,
898+ // Expression::Grouped(_) => todo!(),
899+ // Expression::Index(_) => todo!(),
900+ // Expression::Slice(_) => todo!(),
901+ // Expression::Array(_) => todo!(),
902+ // Expression::Dict(_) => todo!(),
903+ // Expression::DictAccess(_) => todo!(),
904+ // Expression::VimOption(_) => todo!(),
905+ // Expression::Register(_) => todo!(),
906+ // Expression::Lambda(_) => todo!(),
907+ // Expression::Expandable(_) => todo!(),
908+ // Expression::MethodCall(_) => todo!(),
909+ // Expression::Ternary(_) => todo!(),
910+ // Expression::Prefix(_) => todo!(),
911+ // Expression::Infix(_) => todo!(),
912+ }
913+ }
914+
805915impl Generate for VarCommand {
806916 fn gen ( & self , state : & mut State ) -> String {
917+ state. push_declaration (
918+ & self . expr ,
919+ match & self . ty {
920+ Some ( ty) => ty. clone ( ) ,
921+ None => guess_type_of_expr ( state, & self . expr ) ,
922+ } ,
923+ ) ;
924+
807925 let expr = match self . ty {
808- Some ( Type {
809- inner : InnerType :: Bool ,
810- ..
811- } ) => format ! ( "NVIM9.convert.decl_bool({})" , self . expr. gen ( state) ) ,
812- Some ( Type {
813- inner : InnerType :: Dict { .. } ,
814- ..
815- } ) => format ! ( "NVIM9.convert.decl_dict({})" , self . expr. gen ( state) ) ,
926+ Some ( Type :: Bool ) => {
927+ format ! ( "NVIM9.convert.decl_bool({})" , self . expr. gen ( state) )
928+ }
929+ Some ( Type :: Dict { .. } ) => {
930+ format ! ( "NVIM9.convert.decl_dict({})" , self . expr. gen ( state) )
931+ }
816932 _ => self . expr . gen ( state) ,
817933 } ;
818934
@@ -1029,7 +1145,22 @@ impl Generate for PrefixExpression {
10291145 match & self . operator {
10301146 parser:: Operator :: Increment => format ! ( "{right} = {right} + 1" ) ,
10311147 parser:: Operator :: Decrement => format ! ( "{right} = {right} - 1" ) ,
1032- _ => format ! ( "NVIM9.prefix['{:?}']({right})" , self . operator, ) ,
1148+ _ => {
1149+ let ty = guess_type_of_expr ( state, & self . right ) ;
1150+ match ty {
1151+ Type :: Number => {
1152+ let operator = match & self . operator {
1153+ parser:: Operator :: Minus => "-" ,
1154+ _ => todo ! ( "OPERATOR: {:?}" , self . operator) ,
1155+ } ;
1156+
1157+ format ! ( "{operator}{right}" )
1158+ }
1159+ _ => {
1160+ format ! ( "NVIM9.prefix['{:?}']({right})" , self . operator, )
1161+ }
1162+ }
1163+ }
10331164 }
10341165 }
10351166}
@@ -1188,12 +1319,21 @@ impl Generate for VimNumber {
11881319
11891320impl Generate for InfixExpression {
11901321 fn gen ( & self , state : & mut State ) -> String {
1191- format ! (
1192- "NVIM9.ops['{:?}']({}, {})" ,
1193- self . operator,
1194- self . left. gen ( state) ,
1195- self . right. gen ( state)
1196- )
1322+ use Type :: * ;
1323+
1324+ let ty = guess_type_of_expr ( state, & Expression :: Infix ( self . clone ( ) ) ) ;
1325+
1326+ let left = self . left . gen ( state) ;
1327+ let right = self . right . gen ( state) ;
1328+
1329+ if let Some ( literal) = self . operator . literal ( ) {
1330+ match ty {
1331+ Bool => return format ! ( "{left} {literal} {right}" , ) ,
1332+ _ => { }
1333+ }
1334+ }
1335+
1336+ format ! ( "NVIM9.ops['{:?}']({left}, {right})" , self . operator)
11971337
11981338 // match self.operator {
11991339 // Operator::And => gen_operation(
0 commit comments