Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ jobs:

test-linux:
name: Test Linux
runs-on: ubuntu-latest
runs-on: ${{ matrix.config.os }}
strategy:
matrix:
config:
- { os: "ubuntu-latest" }
- { os: "ubuntu-24.04-arm" }
container: ghcr.io/plc-lang/rust-llvm:latest
steps:
- uses: actions/checkout@v3
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/lit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ on:
jobs:
lit-linux-debug:
name: lit tests (Linux, debug build)
runs-on: ubuntu-latest
runs-on: ${{ matrix.config.os }}
strategy:
matrix:
config:
- { os: "ubuntu-latest" }
- { os: "ubuntu-24.04-arm" }
container: ghcr.io/plc-lang/rust-llvm:latest
steps:
- uses: actions/checkout@v3
Expand All @@ -32,4 +37,4 @@ jobs:
- name: Run `build.sh --lit --release`
shell: bash
run: |
./scripts/build.sh --lit --release
./scripts/build.sh --lit --release
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ plc_util = { path = "./compiler/plc_util" }
plc_diagnostics = { path = "./compiler/plc_diagnostics" }
plc_index = { path = "./compiler/plc_index" }
section_mangler = { path = "./compiler/section_mangler" }
plc_llvm = { path = "./compiler/plc_llvm" }
logos = "0.12.0"
clap = { version = "3.0", features = ["derive"] }
indexmap = "2.0"
Expand All @@ -31,6 +32,7 @@ regex = "1"
shell-words = "1.1.0"
plc_derive = { path = "./compiler/plc_derive" }
lld_rs = { git = "https://github.com/mun-lang/lld-rs", rev = "3798ace" }

which = "4.2.5"
log.workspace = true
inkwell.workspace = true
Expand Down Expand Up @@ -79,6 +81,7 @@ members = [
"compiler/plc_index",
"compiler/section_mangler",
"compiler/plc_lowering",
"compiler/plc_llvm",
"tests/test_utils",
]
default-members = [".", "compiler/plc_driver", "compiler/plc_xml"]
Expand Down
43 changes: 43 additions & 0 deletions compiler/plc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,18 @@ impl Pou {
pub fn is_generic(&self) -> bool {
!self.generics.is_empty()
}

pub fn is_stateful(&self) -> bool {
matches!(self.kind, PouType::Program | PouType::FunctionBlock | PouType::Action | PouType::Class)
}

pub fn is_external(&self) -> bool {
matches!(self.linkage, LinkageType::External)
}

pub fn is_built_in(&self) -> bool {
matches!(self.linkage, LinkageType::BuiltIn)
}
}

#[derive(Debug, PartialEq)]
Expand All @@ -313,11 +325,19 @@ pub struct Implementation {
pub access: Option<AccessModifier>,
}

/// Marks declaration and linking requirements for an ast member
#[derive(Debug, Copy, PartialEq, Eq, Clone, Hash)]
pub enum LinkageType {
/// The element is declared in the project currently being complied
Internal,
/// The element is declared externally and being used by the project
External,
/// This indicates an element that should not have any declarations within the compiled project
/// For example a built in function is implied to exist but not declared
BuiltIn,
// TODO: A private linkage indicates an internal element that should not be visible externally
// This is for example a static constructor that should not leak outside its module
// Private,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Expand Down Expand Up @@ -480,6 +500,15 @@ pub enum VariableBlockType {
InOut,
External,
}
impl VariableBlockType {
pub fn is_temp(&self) -> bool {
matches!(self, VariableBlockType::Temp)
}

pub fn is_local(&self) -> bool {
matches!(self, VariableBlockType::Local)
}
}

impl Display for VariableBlockType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Expand Down Expand Up @@ -517,6 +546,11 @@ impl VariableBlock {
VariableBlock::default().with_block_type(VariableBlockType::Global)
}

pub fn with_linkage(mut self, linkage: LinkageType) -> Self {
self.linkage = linkage;
self
}

pub fn with_block_type(mut self, block_type: VariableBlockType) -> Self {
self.kind = block_type;
self
Expand All @@ -526,6 +560,14 @@ impl VariableBlock {
self.variables = variables;
self
}

pub fn is_local(&self) -> bool {
matches!(self.kind, VariableBlockType::Local)
}

pub fn is_temp(&self) -> bool {
matches!(self.kind, VariableBlockType::Temp)
}
}

impl Default for VariableBlock {
Expand Down Expand Up @@ -679,6 +721,7 @@ pub struct UserTypeDeclaration {
pub location: SourceLocation,
/// stores the original scope for compiler-generated types
pub scope: Option<String>,
pub linkage: LinkageType,
}

impl Debug for UserTypeDeclaration {
Expand Down
28 changes: 23 additions & 5 deletions compiler/plc_ast/src/pre_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,13 @@ pub fn pre_process(unit: &mut CompilationUnit, mut id_provider: IdProvider) {
if let DataTypeDeclaration::Definition { mut data_type, location, scope } = *datatype {
data_type.set_name(type_name);
add_nested_datatypes(name, &mut data_type, &mut new_types, &location);
let data_type =
UserTypeDeclaration { data_type: *data_type, initializer: None, location, scope };
let data_type = UserTypeDeclaration {
data_type: *data_type,
initializer: None,
location,
scope,
linkage: crate::ast::LinkageType::Internal,
};
new_types.push(data_type);
}
}
Expand Down Expand Up @@ -289,6 +294,7 @@ fn preprocess_generic_structs(pou: &mut Pou) -> Vec<UserTypeDeclaration> {
initializer: None,
scope: Some(pou.name.clone()),
location: pou.location.clone(),
linkage: crate::ast::LinkageType::Internal,
};
types.push(data_type);
generic_types.insert(binding.name.clone(), new_name);
Expand All @@ -314,8 +320,13 @@ fn preprocess_return_type(pou: &mut Pou, types: &mut Vec<UserTypeDeclaration>) {
if let Some(DataTypeDeclaration::Definition { mut data_type, location, scope }) = datatype {
data_type.set_name(type_name);
add_nested_datatypes(pou.name.as_str(), &mut data_type, types, &location);
let data_type =
UserTypeDeclaration { data_type: *data_type, initializer: None, location, scope };
let data_type = UserTypeDeclaration {
data_type: *data_type,
initializer: None,
location,
scope,
linkage: crate::ast::LinkageType::Internal,
};
types.push(data_type);
}
}
Expand Down Expand Up @@ -350,7 +361,13 @@ fn pre_process_variable_data_type(
// create index entry
add_nested_datatypes(new_type_name.as_str(), &mut data_type, types, &location);
data_type.set_name(new_type_name);
types.push(UserTypeDeclaration { data_type: *data_type, initializer: None, location, scope });
types.push(UserTypeDeclaration {
data_type: *data_type,
initializer: None,
location,
scope,
linkage: crate::ast::LinkageType::Internal,
});
}
//make sure it gets generated
}
Expand Down Expand Up @@ -379,6 +396,7 @@ fn add_nested_datatypes(
initializer: None,
location: location.clone(),
scope,
linkage: crate::ast::LinkageType::Internal,
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/plc_driver/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ pub struct CompileParameters {
name = "no-linker-script",
long,
global = true,
group = "linker_script",
help = "Specify that no linker script should be used"
)]
#[deprecated = "Does nothing"]
pub no_linker_script: bool,

#[clap(
Expand Down
64 changes: 39 additions & 25 deletions compiler/plc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ pub struct LinkOptions {

#[derive(Clone, Default, Debug)]
pub enum LinkerScript {
#[default]
#[deprecated = "No longer used, the default build script is enough"]
Builtin,
Path(String),
#[default]
None,
}

Expand Down Expand Up @@ -155,7 +156,7 @@ pub fn compile_with_pipeline<T: SourceContainer + Clone + 'static>(
mut pipeline: BuildPipeline<T>,
) -> Result<()> {
//register participants
pipeline.register_default_participants();
pipeline.register_default_mut_participants();
let target = pipeline.compile_parameters.as_ref().and_then(|it| it.target.clone()).unwrap_or_default();
let codegen_participant = CodegenParticipant {
compile_options: pipeline.get_compile_options().unwrap(),
Expand Down Expand Up @@ -191,35 +192,48 @@ pub fn parse_and_annotate<T: SourceContainer + Clone>(
name: &str,
src: Vec<T>,
) -> Result<(GlobalContext, AnnotatedProject), Diagnostic> {
let (pipeline, project) = parse_and_annotate_with_diagnostics(name, src, Diagnostician::buffered())
.map_err(|it| Diagnostic::new(it.buffer().unwrap_or_default()))?;
let (pipeline, project) = parse_and_annotate_with_diagnostics(name, src, Diagnostician::buffered())?;
Ok((pipeline.context, project))
}

impl<T: SourceContainer> BuildPipeline<T> {
pub fn from_sources(name: &str, src: Vec<T>, diagnostician: Diagnostician) -> Result<Self, Diagnostic> {
// Parse the source to ast
let project = Project::new(name.to_string()).with_sources(src);
let context = GlobalContext::new().with_source(project.get_sources(), None)?;
let pipeline = BuildPipeline {
context,
project,
diagnostician,
compile_parameters: None,
linker: LinkerType::Internal,
mutable_participants: Vec::default(),
participants: Vec::default(),
module_name: Some("<internal>".to_string()),
};
Ok(pipeline)
}

/// Parses, indexes and annotates the project, returning any diagnostics found along the way
/// Used for tests where we don't want to run the full pipeline
pub fn parse_and_annotate(&mut self) -> Result<AnnotatedProject, Diagnostic> {
let project = self.parse()?;
let project = self.index(project)?;
let project = self.annotate(project)?;
Ok(project)
}
}

pub fn parse_and_annotate_with_diagnostics<T: SourceContainer + Clone>(
name: &str,
src: Vec<T>,
diagnostician: Diagnostician,
) -> Result<(BuildPipeline<T>, AnnotatedProject), Diagnostician> {
) -> Result<(BuildPipeline<T>, AnnotatedProject), Diagnostic> {
// Parse the source to ast
let project = Project::new(name.to_string()).with_sources(src);
let Ok(context) = GlobalContext::new().with_source(project.get_sources(), None) else {
return Err(diagnostician);
};
let mut pipeline = BuildPipeline {
context,
project,
diagnostician,
compile_parameters: None,
linker: LinkerType::Internal,
mutable_participants: Vec::default(),
participants: Vec::default(),
module_name: Some("<internal>".to_string()),
};
pipeline.register_default_participants();
let Ok(project) = pipeline.parse() else { return Err(pipeline.diagnostician) };
let Ok(project) = pipeline.index(project) else { return Err(pipeline.diagnostician) };
let Ok(project) = pipeline.annotate(project) else { return Err(pipeline.diagnostician) };
let mut pipeline = BuildPipeline::from_sources(name, src, diagnostician)?;
pipeline.register_default_mut_participants();
let project = pipeline.parse_and_annotate()?;
let _ = project.validate(&pipeline.context, &mut pipeline.diagnostician);
Ok((pipeline, project))
}

Expand All @@ -229,7 +243,7 @@ pub fn parse_and_validate<T: SourceContainer + Clone>(name: &str, src: Vec<T>) -
let _ = project.validate(&pipeline.context, &mut pipeline.diagnostician);
pipeline.diagnostician.buffer().unwrap()
}
Err(diagnostician) => diagnostician.buffer().unwrap(),
Err(diagnostic) => diagnostic.to_string(),
}
}

Expand Down Expand Up @@ -265,7 +279,7 @@ fn generate_to_string_internal<T: SourceContainer>(
participants: Vec::default(),
module_name: Some("<internal>".to_string()),
};
pipeline.register_default_participants();
pipeline.register_default_mut_participants();
let project = pipeline.parse()?;
let project = pipeline.index(project)?;
let project = pipeline.annotate(project)?;
Expand Down
Loading
Loading