mod element_gen;
mod scope_gen;
pub mod source_map;
use crate::config::LineEnding;
use crate::error::TranspileError;
use pasta_dsl::parser::Span;
use source_map::SourceMapSink;
use std::io::Write;
pub struct LuaCodeGenerator<'a, W: Write> {
writer: &'a mut W,
indent_level: usize,
line_ending: LineEnding,
out_line: u32,
source_map: Option<&'a mut dyn SourceMapSink>,
}
impl<'a, W: Write> LuaCodeGenerator<'a, W> {
pub fn new(writer: &'a mut W) -> Self {
Self {
writer,
indent_level: 0,
line_ending: LineEnding::default(),
out_line: 0,
source_map: None,
}
}
pub fn with_line_ending(writer: &'a mut W, line_ending: LineEnding) -> Self {
Self {
writer,
indent_level: 0,
line_ending,
out_line: 0,
source_map: None,
}
}
pub fn set_source_map(&mut self, sink: &'a mut dyn SourceMapSink) {
self.source_map = Some(sink);
}
pub fn out_line(&self) -> u32 {
self.out_line
}
fn record_span(&mut self, span: Span) {
if let Some(sink) = self.source_map.as_deref_mut() {
if span.is_valid() {
sink.record(self.out_line, span);
}
}
}
fn record_block_line(&mut self, pasta_line: u32) {
if let Some(sink) = self.source_map.as_deref_mut() {
if pasta_line > 0 {
sink.record_line(self.out_line, pasta_line);
}
}
}
fn write_indent(&mut self) -> Result<(), TranspileError> {
let indent = " ".repeat(self.indent_level);
write!(self.writer, "{}", indent)?;
Ok(())
}
fn writeln(&mut self, s: &str) -> Result<(), TranspileError> {
self.write_indent()?;
write!(self.writer, "{}{}", s, self.line_ending.as_str())?;
self.out_line += 1;
Ok(())
}
fn write_blank_line(&mut self) -> Result<(), TranspileError> {
write!(self.writer, "{}", self.line_ending.as_str())?;
self.out_line += 1;
Ok(())
}
fn write_raw(&mut self, s: &str) -> Result<(), TranspileError> {
write!(self.writer, "{}", s)?;
self.out_line += s.matches('\n').count() as u32;
Ok(())
}
fn write_line_terminator(&mut self) -> Result<(), TranspileError> {
writeln!(self.writer)?;
self.out_line += 1;
Ok(())
}
fn indent(&mut self) {
self.indent_level += 1;
}
fn dedent(&mut self) {
if self.indent_level > 0 {
self.indent_level -= 1;
}
}
fn end_block(&mut self) -> Result<(), TranspileError> {
self.dedent();
self.writeln("end")?;
self.write_blank_line()?;
Ok(())
}
pub fn write_header(&mut self) -> Result<(), TranspileError> {
self.writeln("local PASTA = require \"pasta\"")?;
self.writeln("local GLOBAL = require \"pasta.global\"")?;
self.write_blank_line()?;
Ok(())
}
}