Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 34 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 @@ -517,6 +537,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 +551,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 +712,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