use super::*;
use argumenti::*;
impl<'a> Parser<'a> {
pub fn funkcija(&mut self, ime: &Token, izraz: &[Token]) -> Result<Rc<Vozlišče>, Napake> {
let (_, _, izraz) = loči_spredaj(izraz, &["("])
.ok_or(Napake::from_zaporedje(izraz, E5, "Pričakovan '('"))??;
let (parametri_izraz, _, izraz) = loči_spredaj(izraz, &[")"])
.ok_or(Napake::from_zaporedje(izraz, E5, "Pričakovan ')'"))??;
let (tip_izraz, oklepaj, izraz) = loči_spredaj(izraz, &["{"])
.ok_or(Napake::from_zaporedje(izraz, E5, "Pričakovan '{'"))??;
let tip = match tip_izraz {
[] => Ok(Tip::Brez),
[Ločilo("->", ..)] => Err(Napake::from_zaporedje(&[*oklepaj], E5, "Za '->' pričakovan tip")),
[Ločilo("->", ..), ostanek @ ..] => Tip::from(ostanek),
_ => Err(Napake::from_zaporedje(tip_izraz, E5, "Pričakovan '-> <tip>'")),
}?;
let (telo, _, prazno) = loči_zadaj(izraz, &["}"])
.ok_or(Napake::from_zaporedje(izraz, E5, "Pričakovan '}'"))??;
if prazno != [] {
return Err(Napake::from_zaporedje(prazno, E3, "Izraz funkcije se mora zaključiti z '}'"));
}
let vrni = Spremenljivka { tip: tip.clone(), ime: "0_vrni".to_string(), naslov: 0, z_odmikom: true }.rc();
let pc = Spremenljivka { tip: Tip::Celo, ime: "0_PC".to_string(), naslov: vrni.sprememba_stacka(), z_odmikom: true }.rc();
let mut spr_funkcije = HashMap::from([
("0_vrni".to_string(), vrni.clone()),
("0_PC".to_string(), pc.clone()),
]);
let mut naslov_nove = vrni.sprememba_stacka() + pc.sprememba_stacka();
let mut parametri = Vec::new();
let mut napake = Napake::new();
for parameter in parametri_izraz.split(|p| if let Ločilo(",", ..) = p { true } else { false }) {
match parameter {
[] => break,
[Ime(..)] => (),
_ => _ = napake.add_napaka(Napaka::from_zaporedje(parameter, E3, "Neveljavno ime parametra")),
}
let (ime, dvopičje, tip) = loči_spredaj(parameter, &[":"])
.ok_or(Napake::from_zaporedje(parameter, E5, "Pričakovano ':'"))??;
if tip == [] {
return Err(Napake::from_zaporedje(&[*dvopičje], E5, "Za ':' pričakovan tip"))
}
let ime = &ime[0];
let tip = Tip::from(tip)?;
if spr_funkcije.contains_key(ime.as_str()) {
return Err(Napake::from_zaporedje(&[*ime], E7, "Imena parametrov morajo biti unikatna"))
}
else {
let spr = Spremenljivka { tip: tip.clone(), ime: ime.to_string(), naslov: naslov_nove, z_odmikom: true }.rc();
spr_funkcije.insert(ime.to_string(), spr.clone());
parametri.push(spr);
naslov_nove += tip.sprememba_stacka();
}
}
let podpis_funkcije = Self::podpis_funkcije(ime, parametri.iter().map(|p| p.tip()).collect::<Vec<Tip>>().as_slice());
spr_funkcije.insert("0_OF".to_string(), Spremenljivka { tip: Tip::Celo, ime: "0_OF".to_string(), naslov: naslov_nove, z_odmikom: true }.rc());
let mut okolje_funkcije = Parser {
spremenljivke_stack: self.spremenljivke_stack.clone(),
funkcije_stack: self.funkcije_stack.clone(),
reference_stack: self.reference_stack.clone(),
spremenljivke: self.spremenljivke.clone(),
funkcije: self.funkcije.clone(),
št_klicev: self.št_klicev.clone(),
reference: self.reference.clone(),
znotraj_funkcije: true,
};
okolje_funkcije.spremenljivke_stack.push(spr_funkcije.clone());
okolje_funkcije.spremenljivke.extend(spr_funkcije);
okolje_funkcije.funkcije.insert(podpis_funkcije.clone(), Funkcija {
tip: tip.clone(),
ime: podpis_funkcije.clone(),
parametri: parametri.clone(),
telo: Prazno.rc(),
prostor: 0,
}.rc());
let telo = okolje_funkcije.zaporedje(telo)?;
let spr_funkcije = okolje_funkcije.spremenljivke_stack.last().unwrap();
let prostor = spr_funkcije.values().map(|s| s.sprememba_stacka()).sum::<i32>()
- spr_funkcije["0_vrni"].sprememba_stacka()
- spr_funkcije["0_PC"].sprememba_stacka()
- parametri.iter().map(|p| p.sprememba_stacka()).sum::<i32>()
- spr_funkcije["0_OF"].sprememba_stacka();
let fun = Funkcija { tip, ime: podpis_funkcije.clone(), parametri, telo, prostor }.rc();
for (podpis, št_klicev) in okolje_funkcije.št_klicev {
match self.št_klicev.get_mut(&podpis) {
Some(št) => *št += št_klicev,
None => { self.št_klicev.insert(podpis, št_klicev); }
}
}
self.funkcije_stack.last_mut().unwrap().insert(podpis_funkcije.clone(), fun.clone());
self.funkcije.insert(podpis_funkcije, fun.clone());
Ok(fun)
}
pub fn funkcijski_klic_zavrzi_izhod(&mut self, ime: &Token, argumenti: &[Token<'a>]) -> Result<Rc<Vozlišče>, Napake> {
let klic = self.funkcijski_klic(ime, argumenti)?;
let velikost = klic.tip().sprememba_stacka();
Ok(Zaporedje(vec![
klic,
Pop(velikost).rc(),
]).rc())
}
pub fn funkcijski_klic<'b>(&mut self, ime: &Token, argumenti: &'b[Token<'a>]) -> Result<Rc<Vozlišče>, Napake> {
let Argumenti { tipi, spremenljivke, argumenti } = self.argumenti(argumenti)?;
let podpis_funkcije = Self::podpis_funkcije(ime, tipi.as_slice());
let funkcija = self.funkcije.get(&podpis_funkcije)
.ok_or(Napake::from_zaporedje(&[*ime], E2, &format!("Funkcija '{podpis_funkcije}' ne obstaja")))?
.clone();
match self.št_klicev.get_mut(&podpis_funkcije) {
Some(št_klicev) => *št_klicev += 1,
None => { self.št_klicev.insert(podpis_funkcije, 1); },
}
Ok(FunkcijskiKlic { funkcija, spremenljivke: Zaporedje(spremenljivke).rc(), argumenti: Zaporedje(argumenti).rc() }.rc())
}
pub fn multi_klic<'b>(&mut self, ime: &'b Token<'a>, argumenti_izraz: &'b [Token<'a>]) -> Result<Rc<Vozlišče>, Napake> where 'a: 'b {
let Argumenti { tipi, spremenljivke, argumenti } = self.argumenti(argumenti_izraz)?;
let mut funkcijski_klici: Vec<Rc<Vozlišče>> = Vec::new();
let mut napake = Napake::new();
for (tip, (spremenljivka, argument)) in iter::zip(tipi, iter::zip(spremenljivke, argumenti)) {
let podpis_funkcije = Self::podpis_funkcije(ime, &[tip]);
let funkcija = self.funkcije.get(&podpis_funkcije);
match funkcija {
Some(funkcija) => {
funkcijski_klici.push(FunkcijskiKlic {
funkcija: funkcija.clone(),
spremenljivke: Zaporedje(vec![spremenljivka.rc()]).rc(),
argumenti: Zaporedje(vec![argument.rc()]).rc(),
}.rc());
match self.št_klicev.get_mut(&podpis_funkcije) {
Some(št_klicev) => *št_klicev += 1,
None => { self.št_klicev.insert(podpis_funkcije, 1); },
}
},
None => {
napake.add_napaka(Napaka::from_zaporedje(&[*ime], E2,
&format!("Funkcija '{podpis_funkcije}' ne obstaja")));
}
}
}
if napake.prazno() {
Ok(Zaporedje(funkcijski_klici).rc())
}
else {
Err(napake)
}
}
fn podpis_funkcije(ime: &Token, tipi: &[Tip]) -> String {
format!("{}({})", ime.as_str(), tipi.iter()
.map(|t| t.to_string())
.collect::<Vec<String>>()
.join(", "))
}
}